Skip to content

Commit 52fa3ee

Browse files
committed
Merge branch 'make-neighbor-eviction-controllable-by-userspace'
James Prestwood says: ==================== Make neighbor eviction controllable by userspace ==================== Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
2 parents 1d6d336 + f86ca07 commit 52fa3ee

File tree

11 files changed

+281
-2
lines changed

11 files changed

+281
-2
lines changed

Documentation/networking/ip-sysctl.rst

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1611,6 +1611,15 @@ arp_accept - BOOLEAN
16111611
gratuitous arp frame, the arp table will be updated regardless
16121612
if this setting is on or off.
16131613

1614+
arp_evict_nocarrier - BOOLEAN
1615+
Clears the ARP cache on NOCARRIER events. This option is important for
1616+
wireless devices where the ARP cache should not be cleared when roaming
1617+
between access points on the same network. In most cases this should
1618+
remain as the default (1).
1619+
1620+
- 1 - (default): Clear the ARP cache on NOCARRIER events
1621+
- 0 - Do not clear ARP cache on NOCARRIER events
1622+
16141623
mcast_solicit - INTEGER
16151624
The maximum number of multicast probes in INCOMPLETE state,
16161625
when the associated hardware address is unknown. Defaults
@@ -2341,6 +2350,15 @@ ndisc_tclass - INTEGER
23412350

23422351
* 0 - (default)
23432352

2353+
ndisc_evict_nocarrier - BOOLEAN
2354+
Clears the neighbor discovery table on NOCARRIER events. This option is
2355+
important for wireless devices where the neighbor discovery cache should
2356+
not be cleared when roaming between access points on the same network.
2357+
In most cases this should remain as the default (1).
2358+
2359+
- 1 - (default): Clear neighbor discover cache on NOCARRIER events.
2360+
- 0 - Do not clear neighbor discovery cache on NOCARRIER events.
2361+
23442362
mldv1_unsolicited_report_interval - INTEGER
23452363
The interval in milliseconds in which the next unsolicited
23462364
MLDv1 report retransmit will take place.

include/linux/inetdevice.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,8 @@ static inline void ipv4_devconf_setall(struct in_device *in_dev)
133133
#define IN_DEV_ARP_ANNOUNCE(in_dev) IN_DEV_MAXCONF((in_dev), ARP_ANNOUNCE)
134134
#define IN_DEV_ARP_IGNORE(in_dev) IN_DEV_MAXCONF((in_dev), ARP_IGNORE)
135135
#define IN_DEV_ARP_NOTIFY(in_dev) IN_DEV_MAXCONF((in_dev), ARP_NOTIFY)
136+
#define IN_DEV_ARP_EVICT_NOCARRIER(in_dev) IN_DEV_ANDCONF((in_dev), \
137+
ARP_EVICT_NOCARRIER)
136138

137139
struct in_ifaddr {
138140
struct hlist_node hash;

include/linux/ipv6.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ struct ipv6_devconf {
7979
__u32 ioam6_id;
8080
__u32 ioam6_id_wide;
8181
__u8 ioam6_enabled;
82+
__u8 ndisc_evict_nocarrier;
8283

8384
struct ctl_table_header *sysctl_header;
8485
};

include/uapi/linux/ip.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ enum
169169
IPV4_DEVCONF_DROP_UNICAST_IN_L2_MULTICAST,
170170
IPV4_DEVCONF_DROP_GRATUITOUS_ARP,
171171
IPV4_DEVCONF_BC_FORWARDING,
172+
IPV4_DEVCONF_ARP_EVICT_NOCARRIER,
172173
__IPV4_DEVCONF_MAX
173174
};
174175

include/uapi/linux/ipv6.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ enum {
193193
DEVCONF_IOAM6_ENABLED,
194194
DEVCONF_IOAM6_ID,
195195
DEVCONF_IOAM6_ID_WIDE,
196+
DEVCONF_NDISC_EVICT_NOCARRIER,
196197
DEVCONF_MAX
197198
};
198199

include/uapi/linux/sysctl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,7 @@ enum
482482
NET_IPV4_CONF_PROMOTE_SECONDARIES=20,
483483
NET_IPV4_CONF_ARP_ACCEPT=21,
484484
NET_IPV4_CONF_ARP_NOTIFY=22,
485+
NET_IPV4_CONF_ARP_EVICT_NOCARRIER=23,
485486
};
486487

487488
/* /proc/sys/net/ipv4/netfilter */

net/ipv4/arp.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1247,6 +1247,8 @@ static int arp_netdev_event(struct notifier_block *this, unsigned long event,
12471247
{
12481248
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
12491249
struct netdev_notifier_change_info *change_info;
1250+
struct in_device *in_dev;
1251+
bool evict_nocarrier;
12501252

12511253
switch (event) {
12521254
case NETDEV_CHANGEADDR:
@@ -1257,7 +1259,14 @@ static int arp_netdev_event(struct notifier_block *this, unsigned long event,
12571259
change_info = ptr;
12581260
if (change_info->flags_changed & IFF_NOARP)
12591261
neigh_changeaddr(&arp_tbl, dev);
1260-
if (!netif_carrier_ok(dev))
1262+
1263+
in_dev = __in_dev_get_rtnl(dev);
1264+
if (!in_dev)
1265+
evict_nocarrier = true;
1266+
else
1267+
evict_nocarrier = IN_DEV_ARP_EVICT_NOCARRIER(in_dev);
1268+
1269+
if (evict_nocarrier && !netif_carrier_ok(dev))
12611270
neigh_carrier_down(&arp_tbl, dev);
12621271
break;
12631272
default:

net/ipv4/devinet.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ static struct ipv4_devconf ipv4_devconf = {
7575
[IPV4_DEVCONF_SHARED_MEDIA - 1] = 1,
7676
[IPV4_DEVCONF_IGMPV2_UNSOLICITED_REPORT_INTERVAL - 1] = 10000 /*ms*/,
7777
[IPV4_DEVCONF_IGMPV3_UNSOLICITED_REPORT_INTERVAL - 1] = 1000 /*ms*/,
78+
[IPV4_DEVCONF_ARP_EVICT_NOCARRIER - 1] = 1,
7879
},
7980
};
8081

@@ -87,6 +88,7 @@ static struct ipv4_devconf ipv4_devconf_dflt = {
8788
[IPV4_DEVCONF_ACCEPT_SOURCE_ROUTE - 1] = 1,
8889
[IPV4_DEVCONF_IGMPV2_UNSOLICITED_REPORT_INTERVAL - 1] = 10000 /*ms*/,
8990
[IPV4_DEVCONF_IGMPV3_UNSOLICITED_REPORT_INTERVAL - 1] = 1000 /*ms*/,
91+
[IPV4_DEVCONF_ARP_EVICT_NOCARRIER - 1] = 1,
9092
},
9193
};
9294

@@ -2532,6 +2534,8 @@ static struct devinet_sysctl_table {
25322534
DEVINET_SYSCTL_RW_ENTRY(ARP_IGNORE, "arp_ignore"),
25332535
DEVINET_SYSCTL_RW_ENTRY(ARP_ACCEPT, "arp_accept"),
25342536
DEVINET_SYSCTL_RW_ENTRY(ARP_NOTIFY, "arp_notify"),
2537+
DEVINET_SYSCTL_RW_ENTRY(ARP_EVICT_NOCARRIER,
2538+
"arp_evict_nocarrier"),
25352539
DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP_PVLAN, "proxy_arp_pvlan"),
25362540
DEVINET_SYSCTL_RW_ENTRY(FORCE_IGMP_VERSION,
25372541
"force_igmp_version"),

net/ipv6/addrconf.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = {
241241
.ioam6_enabled = 0,
242242
.ioam6_id = IOAM6_DEFAULT_IF_ID,
243243
.ioam6_id_wide = IOAM6_DEFAULT_IF_ID_WIDE,
244+
.ndisc_evict_nocarrier = 1,
244245
};
245246

246247
static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
@@ -300,6 +301,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
300301
.ioam6_enabled = 0,
301302
.ioam6_id = IOAM6_DEFAULT_IF_ID,
302303
.ioam6_id_wide = IOAM6_DEFAULT_IF_ID_WIDE,
304+
.ndisc_evict_nocarrier = 1,
303305
};
304306

305307
/* 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,
55455547
array[DEVCONF_IOAM6_ENABLED] = cnf->ioam6_enabled;
55465548
array[DEVCONF_IOAM6_ID] = cnf->ioam6_id;
55475549
array[DEVCONF_IOAM6_ID_WIDE] = cnf->ioam6_id_wide;
5550+
array[DEVCONF_NDISC_EVICT_NOCARRIER] = cnf->ndisc_evict_nocarrier;
55485551
}
55495552

55505553
static inline size_t inet6_ifla6_size(void)
@@ -6986,6 +6989,15 @@ static const struct ctl_table addrconf_sysctl[] = {
69866989
.mode = 0644,
69876990
.proc_handler = proc_douintvec,
69886991
},
6992+
{
6993+
.procname = "ndisc_evict_nocarrier",
6994+
.data = &ipv6_devconf.ndisc_evict_nocarrier,
6995+
.maxlen = sizeof(u8),
6996+
.mode = 0644,
6997+
.proc_handler = proc_dou8vec_minmax,
6998+
.extra1 = (void *)SYSCTL_ZERO,
6999+
.extra2 = (void *)SYSCTL_ONE,
7000+
},
69897001
{
69907002
/* sentinel */
69917003
}

net/ipv6/ndisc.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1794,6 +1794,7 @@ static int ndisc_netdev_event(struct notifier_block *this, unsigned long event,
17941794
struct netdev_notifier_change_info *change_info;
17951795
struct net *net = dev_net(dev);
17961796
struct inet6_dev *idev;
1797+
bool evict_nocarrier;
17971798

17981799
switch (event) {
17991800
case NETDEV_CHANGEADDR:
@@ -1810,10 +1811,19 @@ static int ndisc_netdev_event(struct notifier_block *this, unsigned long event,
18101811
in6_dev_put(idev);
18111812
break;
18121813
case NETDEV_CHANGE:
1814+
idev = in6_dev_get(dev);
1815+
if (!idev)
1816+
evict_nocarrier = true;
1817+
else {
1818+
evict_nocarrier = idev->cnf.ndisc_evict_nocarrier &&
1819+
net->ipv6.devconf_all->ndisc_evict_nocarrier;
1820+
in6_dev_put(idev);
1821+
}
1822+
18131823
change_info = ptr;
18141824
if (change_info->flags_changed & IFF_NOARP)
18151825
neigh_changeaddr(&nd_tbl, dev);
1816-
if (!netif_carrier_ok(dev))
1826+
if (evict_nocarrier && !netif_carrier_ok(dev))
18171827
neigh_carrier_down(&nd_tbl, dev);
18181828
break;
18191829
case NETDEV_DOWN:

0 commit comments

Comments
 (0)