Skip to content

Commit acb32ba

Browse files
Eric Dumazetdavem330
authored andcommitted
ipv4: reduce percpu needs for icmpmsg mibs
Reading /proc/net/snmp on a machine with a lot of cpus is very expensive (can be ~88000 us). This is because ICMPMSG MIB uses 4096 bytes per cpu, and folding values for all possible cpus can read 16 Mbytes of memory. ICMP messages are not considered as fast path on a typical server, and eventually few cpus handle them anyway. We can afford an atomic operation instead of using percpu data. This saves 4096 bytes per cpu and per network namespace. Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent e56c57d commit acb32ba

File tree

5 files changed

+12
-13
lines changed

5 files changed

+12
-13
lines changed

include/net/icmp.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ struct icmp_err {
3131
extern const struct icmp_err icmp_err_convert[];
3232
#define ICMP_INC_STATS(net, field) SNMP_INC_STATS((net)->mib.icmp_statistics, field)
3333
#define ICMP_INC_STATS_BH(net, field) SNMP_INC_STATS_BH((net)->mib.icmp_statistics, field)
34-
#define ICMPMSGOUT_INC_STATS(net, field) SNMP_INC_STATS((net)->mib.icmpmsg_statistics, field+256)
35-
#define ICMPMSGIN_INC_STATS_BH(net, field) SNMP_INC_STATS_BH((net)->mib.icmpmsg_statistics, field)
34+
#define ICMPMSGOUT_INC_STATS(net, field) SNMP_INC_STATS_ATOMIC_LONG((net)->mib.icmpmsg_statistics, field+256)
35+
#define ICMPMSGIN_INC_STATS_BH(net, field) SNMP_INC_STATS_ATOMIC_LONG((net)->mib.icmpmsg_statistics, field)
3636

3737
struct dst_entry;
3838
struct net_proto_family;

include/net/netns/mib.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ struct netns_mib {
1010
DEFINE_SNMP_STAT(struct udp_mib, udp_statistics);
1111
DEFINE_SNMP_STAT(struct udp_mib, udplite_statistics);
1212
DEFINE_SNMP_STAT(struct icmp_mib, icmp_statistics);
13-
DEFINE_SNMP_STAT(struct icmpmsg_mib, icmpmsg_statistics);
13+
DEFINE_SNMP_STAT_ATOMIC(struct icmpmsg_mib, icmpmsg_statistics);
1414

1515
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
1616
struct proc_dir_entry *proc_net_devsnmp6;

include/net/snmp.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ struct icmp_mib {
6767

6868
#define ICMPMSG_MIB_MAX __ICMPMSG_MIB_MAX
6969
struct icmpmsg_mib {
70-
unsigned long mibs[ICMPMSG_MIB_MAX];
70+
atomic_long_t mibs[ICMPMSG_MIB_MAX];
7171
};
7272

7373
/* ICMP6 (IPv6-ICMP) */

net/ipv4/af_inet.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1572,9 +1572,9 @@ static __net_init int ipv4_mib_init_net(struct net *net)
15721572
sizeof(struct icmp_mib),
15731573
__alignof__(struct icmp_mib)) < 0)
15741574
goto err_icmp_mib;
1575-
if (snmp_mib_init((void __percpu **)net->mib.icmpmsg_statistics,
1576-
sizeof(struct icmpmsg_mib),
1577-
__alignof__(struct icmpmsg_mib)) < 0)
1575+
net->mib.icmpmsg_statistics = kzalloc(sizeof(struct icmpmsg_mib),
1576+
GFP_KERNEL);
1577+
if (!net->mib.icmpmsg_statistics)
15781578
goto err_icmpmsg_mib;
15791579

15801580
tcp_mib_init(net);
@@ -1598,7 +1598,7 @@ static __net_init int ipv4_mib_init_net(struct net *net)
15981598

15991599
static __net_exit void ipv4_mib_exit_net(struct net *net)
16001600
{
1601-
snmp_mib_free((void __percpu **)net->mib.icmpmsg_statistics);
1601+
kfree(net->mib.icmpmsg_statistics);
16021602
snmp_mib_free((void __percpu **)net->mib.icmp_statistics);
16031603
snmp_mib_free((void __percpu **)net->mib.udplite_statistics);
16041604
snmp_mib_free((void __percpu **)net->mib.udp_statistics);

net/ipv4/proc.c

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ static void icmpmsg_put(struct seq_file *seq)
288288

289289
count = 0;
290290
for (i = 0; i < ICMPMSG_MIB_MAX; i++) {
291-
val = snmp_fold_field((void __percpu **) net->mib.icmpmsg_statistics, i);
291+
val = atomic_long_read(&net->mib.icmpmsg_statistics->mibs[i]);
292292
if (val) {
293293
type[count] = i;
294294
vals[count++] = val;
@@ -307,6 +307,7 @@ static void icmp_put(struct seq_file *seq)
307307
{
308308
int i;
309309
struct net *net = seq->private;
310+
atomic_long_t *ptr = net->mib.icmpmsg_statistics->mibs;
310311

311312
seq_puts(seq, "\nIcmp: InMsgs InErrors");
312313
for (i=0; icmpmibmap[i].name != NULL; i++)
@@ -319,15 +320,13 @@ static void icmp_put(struct seq_file *seq)
319320
snmp_fold_field((void __percpu **) net->mib.icmp_statistics, ICMP_MIB_INERRORS));
320321
for (i=0; icmpmibmap[i].name != NULL; i++)
321322
seq_printf(seq, " %lu",
322-
snmp_fold_field((void __percpu **) net->mib.icmpmsg_statistics,
323-
icmpmibmap[i].index));
323+
atomic_long_read(ptr + icmpmibmap[i].index));
324324
seq_printf(seq, " %lu %lu",
325325
snmp_fold_field((void __percpu **) net->mib.icmp_statistics, ICMP_MIB_OUTMSGS),
326326
snmp_fold_field((void __percpu **) net->mib.icmp_statistics, ICMP_MIB_OUTERRORS));
327327
for (i=0; icmpmibmap[i].name != NULL; i++)
328328
seq_printf(seq, " %lu",
329-
snmp_fold_field((void __percpu **) net->mib.icmpmsg_statistics,
330-
icmpmibmap[i].index | 0x100));
329+
atomic_long_read(ptr + (icmpmibmap[i].index | 0x100)));
331330
}
332331

333332
/*

0 commit comments

Comments
 (0)