[PATCH 1/3 net-next v5] ipv4: centralize devconf sysctl handling
From: Fernando Fernandez Mancera <hidden>
Date: 2026-06-07 11:01:44
Subsystem:
networking [general], networking [ipv4/ipv6], the rest · Maintainers:
"David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, David Ahern, Ido Schimmel, Linus Torvalds
The logic for handling IPv4 devconf sysctls is scattered. Notification
and cache flushes are managed in devinet_conf_proc(), while a separate
ipv4_doint_and_flush() function and DEVINET_SYSCTL_FLUSHING_ENTRY macro
is used for properties that solely require a cache flush.
This patch refactors the sysctl handling by introducing a centralized
helper, devinet_conf_post_set(). This new function evaluates the changed
attribute and handles all necessary operations like triggering netlink
notifications. It returns a boolean indicating whether a routing cache
flush is required.
Note that the boolean is necessary as this function will be re-used for
netlink IPv4 devconf handling where the cache flushing must wait until
all the attributes have been processed.
Finally, this is introducing a small change in behavior for
IPV4_DEVCONF_ROUTE_LOCALNET. As commit d0daebc3d622 ("ipv4: Add
interface option to enable routing of 127.0.0.0/8") intended, the cache
flush should only be performed when ROUTE_LOCALNET changes from 1 to 0.
Unfortunately, this was not true because while implementing it the
DEVINET_SYSCTL_FLUSHING_ENTRY was used for the attribute, making the
code related to it on devinet_conf_proc() dead.
IPV4_DEVCONF_FORWARDING is still being handled separately as it requires
more operations.
Reviewed-by: Nicolas Dichtel <redacted>
Signed-off-by: Fernando Fernandez Mancera <redacted>
---
v2: no changes
v3: no changes
v4: no changes
v5: no changes
---
net/ipv4/devinet.c | 127 ++++++++++++++++++++++++---------------------
1 file changed, 68 insertions(+), 59 deletions(-)
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index 58fe7cb69545..8300516fb38f 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c@@ -2128,6 +2128,46 @@ static int inet_validate_link_af(const struct net_device *dev, return 0; } +static bool devinet_conf_post_set(struct net *net, struct ipv4_devconf *cnf, + int attr, int new, int old, int ifindex) +{ + if (new == old) + return false; + + switch (attr) { + case IPV4_DEVCONF_ROUTE_LOCALNET: + case IPV4_DEVCONF_ACCEPT_LOCAL: + if (new == 0) + return true; + break; + case IPV4_DEVCONF_NOXFRM: + case IPV4_DEVCONF_NOPOLICY: + case IPV4_DEVCONF_PROMOTE_SECONDARIES: + case IPV4_DEVCONF_DROP_UNICAST_IN_L2_MULTICAST: + case IPV4_DEVCONF_BC_FORWARDING: + return true; + case IPV4_DEVCONF_RP_FILTER: + inet_netconf_notify_devconf(net, RTM_NEWNETCONF, + NETCONFA_RP_FILTER, + ifindex, cnf); + break; + case IPV4_DEVCONF_PROXY_ARP: + inet_netconf_notify_devconf(net, RTM_NEWNETCONF, + NETCONFA_PROXY_NEIGH, + ifindex, cnf); + break; + case IPV4_DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN: + inet_netconf_notify_devconf(net, RTM_NEWNETCONF, + NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN, + ifindex, cnf); + break; + default: + break; + } + + return false; +} + static int inet_set_link_af(struct net_device *dev, const struct nlattr *nla, struct netlink_ext_ack *extack) {
@@ -2509,44 +2549,31 @@ static int devinet_conf_proc(const struct ctl_table *ctl, int write, if (write) { struct ipv4_devconf *cnf = ctl->extra1; - struct net *net = ctl->extra2; int i = (int *)ctl->data - cnf->data; + struct net *net = ctl->extra2; int ifindex; - set_bit(i, cnf->state); - - if (cnf == net->ipv4.devconf_dflt) - devinet_copy_dflt_conf(net, i); - if (i == IPV4_DEVCONF_ACCEPT_LOCAL - 1 || - i == IPV4_DEVCONF_ROUTE_LOCALNET - 1) - if ((new_value == 0) && (old_value != 0)) - rt_cache_flush(net); + /* These attributes are bypassing the tracking state, + * for the rest track the state and propagate the changes + * to default config + */ + switch (i + 1) { + case IPV4_DEVCONF_NOXFRM: + case IPV4_DEVCONF_NOPOLICY: + case IPV4_DEVCONF_PROMOTE_SECONDARIES: + case IPV4_DEVCONF_DROP_UNICAST_IN_L2_MULTICAST: + break; + default: + set_bit(i, cnf->state); + if (cnf == net->ipv4.devconf_dflt) + devinet_copy_dflt_conf(net, i); + break; + } - if (i == IPV4_DEVCONF_BC_FORWARDING - 1 && - new_value != old_value) + ifindex = devinet_conf_ifindex(net, cnf); + if (devinet_conf_post_set(net, cnf, i + 1, new_value, + old_value, ifindex)) rt_cache_flush(net); - - if (i == IPV4_DEVCONF_RP_FILTER - 1 && - new_value != old_value) { - ifindex = devinet_conf_ifindex(net, cnf); - inet_netconf_notify_devconf(net, RTM_NEWNETCONF, - NETCONFA_RP_FILTER, - ifindex, cnf); - } - if (i == IPV4_DEVCONF_PROXY_ARP - 1 && - new_value != old_value) { - ifindex = devinet_conf_ifindex(net, cnf); - inet_netconf_notify_devconf(net, RTM_NEWNETCONF, - NETCONFA_PROXY_NEIGH, - ifindex, cnf); - } - if (i == IPV4_DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN - 1 && - new_value != old_value) { - ifindex = devinet_conf_ifindex(net, cnf); - inet_netconf_notify_devconf(net, RTM_NEWNETCONF, - NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN, - ifindex, cnf); - } } return ret;
@@ -2599,20 +2626,6 @@ static int devinet_sysctl_forward(const struct ctl_table *ctl, int write, return ret; } -static int ipv4_doint_and_flush(const struct ctl_table *ctl, int write, - void *buffer, size_t *lenp, loff_t *ppos) -{ - int *valp = ctl->data; - int val = *valp; - int ret = proc_dointvec(ctl, write, buffer, lenp, ppos); - struct net *net = ctl->extra2; - - if (write && *valp != val) - rt_cache_flush(net); - - return ret; -} - #define DEVINET_SYSCTL_ENTRY(attr, name, mval, proc) \ { \ .procname = name, \
@@ -2633,9 +2646,6 @@ static int ipv4_doint_and_flush(const struct ctl_table *ctl, int write, #define DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, proc) \ DEVINET_SYSCTL_ENTRY(attr, name, 0644, proc) -#define DEVINET_SYSCTL_FLUSHING_ENTRY(attr, name) \ - DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, ipv4_doint_and_flush) - static struct devinet_sysctl_table { struct ctl_table_header *sysctl_header; struct ctl_table devinet_vars[IPV4_DEVCONF_MAX];
@@ -2678,15 +2688,14 @@ static struct devinet_sysctl_table { "ignore_routes_with_linkdown"), DEVINET_SYSCTL_RW_ENTRY(DROP_GRATUITOUS_ARP, "drop_gratuitous_arp"), - - DEVINET_SYSCTL_FLUSHING_ENTRY(NOXFRM, "disable_xfrm"), - DEVINET_SYSCTL_FLUSHING_ENTRY(NOPOLICY, "disable_policy"), - DEVINET_SYSCTL_FLUSHING_ENTRY(PROMOTE_SECONDARIES, - "promote_secondaries"), - DEVINET_SYSCTL_FLUSHING_ENTRY(ROUTE_LOCALNET, - "route_localnet"), - DEVINET_SYSCTL_FLUSHING_ENTRY(DROP_UNICAST_IN_L2_MULTICAST, - "drop_unicast_in_l2_multicast"), + DEVINET_SYSCTL_RW_ENTRY(NOXFRM, "disable_xfrm"), + DEVINET_SYSCTL_RW_ENTRY(NOPOLICY, "disable_policy"), + DEVINET_SYSCTL_RW_ENTRY(PROMOTE_SECONDARIES, + "promote_secondaries"), + DEVINET_SYSCTL_RW_ENTRY(ROUTE_LOCALNET, + "route_localnet"), + DEVINET_SYSCTL_RW_ENTRY(DROP_UNICAST_IN_L2_MULTICAST, + "drop_unicast_in_l2_multicast"), }, };
--
2.54.0