47

In sysctl, the /proc/sys/net/ipv[46]/conf/ keys have the following subkeys: all, default, and a key for each network interface. For example, on a machine with a single network interface eth0, it will look like this:

iserv ~ # ll /proc/sys/net/ipv[46]/conf/
/proc/sys/net/ipv4/conf/:
insgesamt 0
dr-xr-xr-x 0 root root 0 12. Sep 23:30 all/
dr-xr-xr-x 0 root root 0 12. Sep 23:30 default/
dr-xr-xr-x 0 root root 0 12. Sep 23:30 eth0/
dr-xr-xr-x 0 root root 0 12. Sep 23:30 lo/

/proc/sys/net/ipv6/conf/:
insgesamt 0
dr-xr-xr-x 0 root root 0 12. Sep 23:30 all/
dr-xr-xr-x 0 root root 0 12. Sep 23:30 default/
dr-xr-xr-x 0 root root 0 12. Sep 23:30 eth0/
dr-xr-xr-x 0 root root 0 12. Sep 23:30 lo/

All the respective settings exist in each key separately. For example, if I want to disable IPv6 Router Advertisements with the accept_ra value, this value exists four times:

iserv ~ # sysctl -a 2>/dev/null | grep "accept_ra "
net.ipv6.conf.all.accept_ra = 1
net.ipv6.conf.default.accept_ra = 1
net.ipv6.conf.lo.accept_ra = 1
net.ipv6.conf.eth0.accept_ra = 1

My question now is: which of these values do I need to change? I figured all (to change all existing interfaces) and default (to change all new interfaces that may appear later), but changing these still leaves the value at 1 for lo and eth0:

iserv ~ # sysctl -w net.ipv6.conf.all.accept_ra=0
net.ipv6.conf.all.accept_ra = 0
iserv ~ # sysctl -w net.ipv6.conf.default.accept_ra=0
net.ipv6.conf.default.accept_ra = 0
iserv ~ # sysctl -a 2>/dev/null | grep "accept_ra "  
net.ipv6.conf.all.accept_ra = 0
net.ipv6.conf.default.accept_ra = 0
net.ipv6.conf.lo.accept_ra = 1
net.ipv6.conf.eth0.accept_ra = 1

Will the machine now accept Router Advertisements on eth0, or will it not?

2

3 Answers 3

44

I've found the answer while still writing the question. I've decided to post it anyway because others may find this insightful, and then answer it myself; I hope this is not frowned upon :)

The user Philipp Matthias Hahn on the linux-kernel mailing list has figured it out at least partially:

As far as I researched for IPv4 some time ago, the "default" value gets
copied to newly created interfaces only once.
"all" on the other hand allways gets applied in addition to the current
setting, but it depends on the exact setting, if its ORed, ANDed, or
whatevered:
    log_martians         OR
    accept_redirects     AND
    forwarding           ?
    mc_forwarding        AND
    medium_id
    proxy_arp            OR
    shared_media         OR
    secure_redirects     OR
    send_redirects       OR
    bootp_relay          AND
    accept_source_route  AND
    rp_filter            AND
    arp_filter           OR
    arp_announce         MAX
    arp_ignore           MAX
    arp_accept
    app_solicit
    disable_policy
    disable_xfrm
    tag
(see include/linux/inetdevice.h:83 for IN_DEV_{AND,OR,MAX}CONF)

Putting a new value in "all" doesn't change the value you read from
"$interface", but it only gets computed and used internally.

He doesn't cover accept_ra but at least it's clear now how all and default work, or rather, how they do not work as I would have expected.

4
8

I'm going to supply a new answer to this question, since many Google search results lead here, and the internet has a lot of outdated information and misinformation about this.

net.ipv{4,6}.conf.default.*

@Martin von Wittich's correct about the behavior of default-- it's applied to new interfaces only. For a host's interfaces, the default setting will only apply when new devices are created, and host interfaces are traditionally only created at boot time. Therefore, if you simply change the default parameter, the value isn't applied to the host interfaces until the host is rebooted.

The behavior is different for containers, Kubernetes and CNI. New container interfaces are created all the time. Therefore if you simply change the default parameter it will apply to new interfaces created by new containers, but not for existing container interfaces and not for host interfaces. This can be very confusing!

net.ipv{4,6}.conf.all.* vs. net.ipv{4,6}.conf.<net device>.*

The behavior of net.ipv{4,6}.conf.all.*, is different depending on the which parameter is being changed, as pointed out by @gaia & @odivlad. The real answer is in the Kernel's documentation and has changed over time (as with rp_filter, which is a popular parameter for multi-homed systems). Martin's answer above is was on the right track but is now out of date.

The behavior for this feature is documented in the Kernel documentation, which you can find at https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt or https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/Documentation/networking/ip-sysctl.txt?h=linux-4.15.y (Select your particular Kernel version in the upper right-hand corner).

For example, the value for rp_filter will be MAXed (not ANDed as stated previously):

The max value from conf/{all,interface}/rp_filter is used
when doing source validation on the {interface}.

arp_filter, on the other hand, is ORed:

arp_filter for the interface will be enabled if at least one of
conf/{all,interface}/arp_filter is set to TRUE,
it will be disabled otherwise

But what about accept_ra? Well, Kernel 4.15 documentation doesn't state the behavior in that case, and it's actually not allowed any more on a per-interface basis IIRC. It used to be allowed in Kernel 2.6 (CentOS 6, etc).

3
  • 2
    Thanks for providing the update! I've made this the accepted answer to increase the visibility. Aug 31, 2021 at 11:05
  • Thanks Martin! It's amazing how hard it is to find answers to these simple questions. I used your answer below for years. Aug 31, 2021 at 20:15
  • 1
    Thanks, your answer does help a lot! Nov 19, 2021 at 10:02
7

The handler for accept_ra in net/ipv6/addrconf.c is proc_dointvec. So generic interface code has previously generated an array of all and interface-specific entries, and writing into these with sysctl or procfs just puts the value you specify in the array.

We are concerned with how those values are then used

You'll see from callers of ipv6_accept_ra() function in include/net/ipv6.h that every caller uses a specific interface to call that function.

So there is nowhere in the kernel that net.ipv6.conf.all.accept_ra is ever used except to store a procfs entry, as far as I can see.

If you want to change accept_ra of every interface with one command, you can do this:

for TUNABLE in $(sysctl -aN --pattern "accept_ra$")
do
    sysctl -w "$TUNABLE=0"
done

I'm about 4 years late but this is the correct answer :P

1
  • sysctl (procps version 3.2.8): error: Unknown parameter "-aN"
    – qin
    Jul 19, 2019 at 2:09

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .