Skip to content

Commit

Permalink
Merge branch 'make-neighbor-eviction-controllable-by-userspace'
Browse files Browse the repository at this point in the history
James Prestwood says:

====================
Make neighbor eviction controllable by userspace
====================

Link: https://lore.kernel.org/r/20211101173630.300969-1-prestwoj@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
  • Loading branch information
Jakub Kicinski committed Nov 2, 2021
2 parents 1d6d336 + f86ca07 commit 52fa3ee
Show file tree
Hide file tree
Showing 11 changed files with 281 additions and 2 deletions.
18 changes: 18 additions & 0 deletions Documentation/networking/ip-sysctl.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1611,6 +1611,15 @@ arp_accept - BOOLEAN
gratuitous arp frame, the arp table will be updated regardless
if this setting is on or off.

arp_evict_nocarrier - BOOLEAN
Clears the ARP cache on NOCARRIER events. This option is important for
wireless devices where the ARP 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 the ARP cache on NOCARRIER events
- 0 - Do not clear ARP cache on NOCARRIER events

mcast_solicit - INTEGER
The maximum number of multicast probes in INCOMPLETE state,
when the associated hardware address is unknown. Defaults
Expand Down Expand Up @@ -2341,6 +2350,15 @@ ndisc_tclass - INTEGER

* 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
The interval in milliseconds in which the next unsolicited
MLDv1 report retransmit will take place.
Expand Down
2 changes: 2 additions & 0 deletions include/linux/inetdevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ static inline void ipv4_devconf_setall(struct in_device *in_dev)
#define IN_DEV_ARP_ANNOUNCE(in_dev) IN_DEV_MAXCONF((in_dev), ARP_ANNOUNCE)
#define IN_DEV_ARP_IGNORE(in_dev) IN_DEV_MAXCONF((in_dev), ARP_IGNORE)
#define IN_DEV_ARP_NOTIFY(in_dev) IN_DEV_MAXCONF((in_dev), ARP_NOTIFY)
#define IN_DEV_ARP_EVICT_NOCARRIER(in_dev) IN_DEV_ANDCONF((in_dev), \
ARP_EVICT_NOCARRIER)

struct in_ifaddr {
struct hlist_node hash;
Expand Down
1 change: 1 addition & 0 deletions include/linux/ipv6.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ struct ipv6_devconf {
__u32 ioam6_id;
__u32 ioam6_id_wide;
__u8 ioam6_enabled;
__u8 ndisc_evict_nocarrier;

struct ctl_table_header *sysctl_header;
};
Expand Down
1 change: 1 addition & 0 deletions include/uapi/linux/ip.h
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ enum
IPV4_DEVCONF_DROP_UNICAST_IN_L2_MULTICAST,
IPV4_DEVCONF_DROP_GRATUITOUS_ARP,
IPV4_DEVCONF_BC_FORWARDING,
IPV4_DEVCONF_ARP_EVICT_NOCARRIER,
__IPV4_DEVCONF_MAX
};

Expand Down
1 change: 1 addition & 0 deletions include/uapi/linux/ipv6.h
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ enum {
DEVCONF_IOAM6_ENABLED,
DEVCONF_IOAM6_ID,
DEVCONF_IOAM6_ID_WIDE,
DEVCONF_NDISC_EVICT_NOCARRIER,
DEVCONF_MAX
};

Expand Down
1 change: 1 addition & 0 deletions include/uapi/linux/sysctl.h
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,7 @@ enum
NET_IPV4_CONF_PROMOTE_SECONDARIES=20,
NET_IPV4_CONF_ARP_ACCEPT=21,
NET_IPV4_CONF_ARP_NOTIFY=22,
NET_IPV4_CONF_ARP_EVICT_NOCARRIER=23,
};

/* /proc/sys/net/ipv4/netfilter */
Expand Down
11 changes: 10 additions & 1 deletion net/ipv4/arp.c
Original file line number Diff line number Diff line change
Expand Up @@ -1247,6 +1247,8 @@ static int arp_netdev_event(struct notifier_block *this, unsigned long event,
{
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
struct netdev_notifier_change_info *change_info;
struct in_device *in_dev;
bool evict_nocarrier;

switch (event) {
case NETDEV_CHANGEADDR:
Expand All @@ -1257,7 +1259,14 @@ static int arp_netdev_event(struct notifier_block *this, unsigned long event,
change_info = ptr;
if (change_info->flags_changed & IFF_NOARP)
neigh_changeaddr(&arp_tbl, dev);
if (!netif_carrier_ok(dev))

in_dev = __in_dev_get_rtnl(dev);
if (!in_dev)
evict_nocarrier = true;
else
evict_nocarrier = IN_DEV_ARP_EVICT_NOCARRIER(in_dev);

if (evict_nocarrier && !netif_carrier_ok(dev))
neigh_carrier_down(&arp_tbl, dev);
break;
default:
Expand Down
4 changes: 4 additions & 0 deletions net/ipv4/devinet.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ static struct ipv4_devconf ipv4_devconf = {
[IPV4_DEVCONF_SHARED_MEDIA - 1] = 1,
[IPV4_DEVCONF_IGMPV2_UNSOLICITED_REPORT_INTERVAL - 1] = 10000 /*ms*/,
[IPV4_DEVCONF_IGMPV3_UNSOLICITED_REPORT_INTERVAL - 1] = 1000 /*ms*/,
[IPV4_DEVCONF_ARP_EVICT_NOCARRIER - 1] = 1,
},
};

Expand All @@ -87,6 +88,7 @@ static struct ipv4_devconf ipv4_devconf_dflt = {
[IPV4_DEVCONF_ACCEPT_SOURCE_ROUTE - 1] = 1,
[IPV4_DEVCONF_IGMPV2_UNSOLICITED_REPORT_INTERVAL - 1] = 10000 /*ms*/,
[IPV4_DEVCONF_IGMPV3_UNSOLICITED_REPORT_INTERVAL - 1] = 1000 /*ms*/,
[IPV4_DEVCONF_ARP_EVICT_NOCARRIER - 1] = 1,
},
};

Expand Down Expand Up @@ -2532,6 +2534,8 @@ static struct devinet_sysctl_table {
DEVINET_SYSCTL_RW_ENTRY(ARP_IGNORE, "arp_ignore"),
DEVINET_SYSCTL_RW_ENTRY(ARP_ACCEPT, "arp_accept"),
DEVINET_SYSCTL_RW_ENTRY(ARP_NOTIFY, "arp_notify"),
DEVINET_SYSCTL_RW_ENTRY(ARP_EVICT_NOCARRIER,
"arp_evict_nocarrier"),
DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP_PVLAN, "proxy_arp_pvlan"),
DEVINET_SYSCTL_RW_ENTRY(FORCE_IGMP_VERSION,
"force_igmp_version"),
Expand Down
12 changes: 12 additions & 0 deletions net/ipv6/addrconf.c
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = {
.ioam6_enabled = 0,
.ioam6_id = IOAM6_DEFAULT_IF_ID,
.ioam6_id_wide = IOAM6_DEFAULT_IF_ID_WIDE,
.ndisc_evict_nocarrier = 1,
};

static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
Expand Down Expand Up @@ -300,6 +301,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
.ioam6_enabled = 0,
.ioam6_id = IOAM6_DEFAULT_IF_ID,
.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 */
Expand Down Expand Up @@ -5545,6 +5547,7 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
array[DEVCONF_IOAM6_ENABLED] = cnf->ioam6_enabled;
array[DEVCONF_IOAM6_ID] = cnf->ioam6_id;
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)
Expand Down Expand Up @@ -6986,6 +6989,15 @@ static const struct ctl_table addrconf_sysctl[] = {
.mode = 0644,
.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 */
}
Expand Down
12 changes: 11 additions & 1 deletion net/ipv6/ndisc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1794,6 +1794,7 @@ static int ndisc_netdev_event(struct notifier_block *this, unsigned long event,
struct netdev_notifier_change_info *change_info;
struct net *net = dev_net(dev);
struct inet6_dev *idev;
bool evict_nocarrier;

switch (event) {
case NETDEV_CHANGEADDR:
Expand All @@ -1810,10 +1811,19 @@ static int ndisc_netdev_event(struct notifier_block *this, unsigned long event,
in6_dev_put(idev);
break;
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;
if (change_info->flags_changed & IFF_NOARP)
neigh_changeaddr(&nd_tbl, dev);
if (!netif_carrier_ok(dev))
if (evict_nocarrier && !netif_carrier_ok(dev))
neigh_carrier_down(&nd_tbl, dev);
break;
case NETDEV_DOWN:
Expand Down
Loading

0 comments on commit 52fa3ee

Please sign in to comment.