2
0
mirror of https://github.com/edk2-porting/linux-next.git synced 2024-12-15 16:53:54 +08:00

net: ndisc: introduce ndisc_evict_nocarrier sysctl parameter

In most situations the neighbor discovery cache should be cleared on a
NOCARRIER event which is currently done unconditionally. But for wireless
roams the neighbor discovery cache can and should remain intact since
the underlying network has not changed.

This patch introduces a sysctl option ndisc_evict_nocarrier which can
be disabled by a wireless supplicant during a roam. This allows packets
to be sent after a roam immediately without having to wait for
neighbor discovery.

A user reported roughly a 1 second delay after a roam before packets
could be sent out (note, on IPv4). This delay was due to the ARP
cache being cleared. During testing of this same scenario using IPv6
no delay was noticed, but regardless there is no reason to clear
the ndisc cache for wireless roams.

Signed-off-by: James Prestwood <prestwoj@gmail.com>
Reviewed-by: David Ahern <dsahern@kernel.org>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
James Prestwood 2021-11-01 10:36:29 -07:00 committed by Jakub Kicinski
parent fcdb44d08a
commit 18ac597af2
5 changed files with 34 additions and 1 deletions

View File

@ -2350,6 +2350,15 @@ ndisc_tclass - INTEGER
* 0 - (default) * 0 - (default)
ndisc_evict_nocarrier - BOOLEAN
Clears the neighbor discovery table on NOCARRIER events. This option is
important for wireless devices where the neighbor discovery cache should
not be cleared when roaming between access points on the same network.
In most cases this should remain as the default (1).
- 1 - (default): Clear neighbor discover cache on NOCARRIER events.
- 0 - Do not clear neighbor discovery cache on NOCARRIER events.
mldv1_unsolicited_report_interval - INTEGER mldv1_unsolicited_report_interval - INTEGER
The interval in milliseconds in which the next unsolicited The interval in milliseconds in which the next unsolicited
MLDv1 report retransmit will take place. MLDv1 report retransmit will take place.

View File

@ -79,6 +79,7 @@ struct ipv6_devconf {
__u32 ioam6_id; __u32 ioam6_id;
__u32 ioam6_id_wide; __u32 ioam6_id_wide;
__u8 ioam6_enabled; __u8 ioam6_enabled;
__u8 ndisc_evict_nocarrier;
struct ctl_table_header *sysctl_header; struct ctl_table_header *sysctl_header;
}; };

View File

@ -193,6 +193,7 @@ enum {
DEVCONF_IOAM6_ENABLED, DEVCONF_IOAM6_ENABLED,
DEVCONF_IOAM6_ID, DEVCONF_IOAM6_ID,
DEVCONF_IOAM6_ID_WIDE, DEVCONF_IOAM6_ID_WIDE,
DEVCONF_NDISC_EVICT_NOCARRIER,
DEVCONF_MAX DEVCONF_MAX
}; };

View File

@ -241,6 +241,7 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = {
.ioam6_enabled = 0, .ioam6_enabled = 0,
.ioam6_id = IOAM6_DEFAULT_IF_ID, .ioam6_id = IOAM6_DEFAULT_IF_ID,
.ioam6_id_wide = IOAM6_DEFAULT_IF_ID_WIDE, .ioam6_id_wide = IOAM6_DEFAULT_IF_ID_WIDE,
.ndisc_evict_nocarrier = 1,
}; };
static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
@ -300,6 +301,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
.ioam6_enabled = 0, .ioam6_enabled = 0,
.ioam6_id = IOAM6_DEFAULT_IF_ID, .ioam6_id = IOAM6_DEFAULT_IF_ID,
.ioam6_id_wide = IOAM6_DEFAULT_IF_ID_WIDE, .ioam6_id_wide = IOAM6_DEFAULT_IF_ID_WIDE,
.ndisc_evict_nocarrier = 1,
}; };
/* Check if link is ready: is it up and is a valid qdisc available */ /* Check if link is ready: is it up and is a valid qdisc available */
@ -5545,6 +5547,7 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
array[DEVCONF_IOAM6_ENABLED] = cnf->ioam6_enabled; array[DEVCONF_IOAM6_ENABLED] = cnf->ioam6_enabled;
array[DEVCONF_IOAM6_ID] = cnf->ioam6_id; array[DEVCONF_IOAM6_ID] = cnf->ioam6_id;
array[DEVCONF_IOAM6_ID_WIDE] = cnf->ioam6_id_wide; array[DEVCONF_IOAM6_ID_WIDE] = cnf->ioam6_id_wide;
array[DEVCONF_NDISC_EVICT_NOCARRIER] = cnf->ndisc_evict_nocarrier;
} }
static inline size_t inet6_ifla6_size(void) static inline size_t inet6_ifla6_size(void)
@ -6986,6 +6989,15 @@ static const struct ctl_table addrconf_sysctl[] = {
.mode = 0644, .mode = 0644,
.proc_handler = proc_douintvec, .proc_handler = proc_douintvec,
}, },
{
.procname = "ndisc_evict_nocarrier",
.data = &ipv6_devconf.ndisc_evict_nocarrier,
.maxlen = sizeof(u8),
.mode = 0644,
.proc_handler = proc_dou8vec_minmax,
.extra1 = (void *)SYSCTL_ZERO,
.extra2 = (void *)SYSCTL_ONE,
},
{ {
/* sentinel */ /* sentinel */
} }

View File

@ -1794,6 +1794,7 @@ static int ndisc_netdev_event(struct notifier_block *this, unsigned long event,
struct netdev_notifier_change_info *change_info; struct netdev_notifier_change_info *change_info;
struct net *net = dev_net(dev); struct net *net = dev_net(dev);
struct inet6_dev *idev; struct inet6_dev *idev;
bool evict_nocarrier;
switch (event) { switch (event) {
case NETDEV_CHANGEADDR: case NETDEV_CHANGEADDR:
@ -1810,10 +1811,19 @@ static int ndisc_netdev_event(struct notifier_block *this, unsigned long event,
in6_dev_put(idev); in6_dev_put(idev);
break; break;
case NETDEV_CHANGE: case NETDEV_CHANGE:
idev = in6_dev_get(dev);
if (!idev)
evict_nocarrier = true;
else {
evict_nocarrier = idev->cnf.ndisc_evict_nocarrier &&
net->ipv6.devconf_all->ndisc_evict_nocarrier;
in6_dev_put(idev);
}
change_info = ptr; change_info = ptr;
if (change_info->flags_changed & IFF_NOARP) if (change_info->flags_changed & IFF_NOARP)
neigh_changeaddr(&nd_tbl, dev); neigh_changeaddr(&nd_tbl, dev);
if (!netif_carrier_ok(dev)) if (evict_nocarrier && !netif_carrier_ok(dev))
neigh_carrier_down(&nd_tbl, dev); neigh_carrier_down(&nd_tbl, dev);
break; break;
case NETDEV_DOWN: case NETDEV_DOWN: