ipv4: centralize devconf sysctl handling
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 d0daebc3d6 ("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 <nicolas.dichtel@6wind.com>
Signed-off-by: Fernando Fernandez Mancera <fmancera@suse.de>
Link: https://patch.msgid.link/20260609204520.4670-1-fmancera@suse.de
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
1 parent
91934d4446
commit
3a29b55505
1 file changed
+62
-53
+62
-53
@@ -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;
|
||||
|
||||
/* 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);
|
||||
if (i == IPV4_DEVCONF_ACCEPT_LOCAL - 1 ||
|
||||
i == IPV4_DEVCONF_ROUTE_LOCALNET - 1)
|
||||
if ((new_value == 0) && (old_value != 0))
|
||||
rt_cache_flush(net);
|
||||
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,14 +2688,13 @@ 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,
|
||||
DEVINET_SYSCTL_RW_ENTRY(NOXFRM, "disable_xfrm"),
|
||||
DEVINET_SYSCTL_RW_ENTRY(NOPOLICY, "disable_policy"),
|
||||
DEVINET_SYSCTL_RW_ENTRY(PROMOTE_SECONDARIES,
|
||||
"promote_secondaries"),
|
||||
DEVINET_SYSCTL_FLUSHING_ENTRY(ROUTE_LOCALNET,
|
||||
DEVINET_SYSCTL_RW_ENTRY(ROUTE_LOCALNET,
|
||||
"route_localnet"),
|
||||
DEVINET_SYSCTL_FLUSHING_ENTRY(DROP_UNICAST_IN_L2_MULTICAST,
|
||||
DEVINET_SYSCTL_RW_ENTRY(DROP_UNICAST_IN_L2_MULTICAST,
|
||||
"drop_unicast_in_l2_multicast"),
|
||||
},
|
||||
};
|
||||
|
||||
Reference in new issue
Block a user