aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/af_inet.c36
-rw-r--r--net/ipv4/proc.c15
-rw-r--r--net/ipv6/addrconf.c18
-rw-r--r--net/ipv6/proc.c17
4 files changed, 76 insertions, 10 deletions
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 640db9b90330..3ceb025b16f2 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -1427,6 +1427,42 @@ unsigned long snmp_fold_field(void __percpu *mib[], int offt)
1427} 1427}
1428EXPORT_SYMBOL_GPL(snmp_fold_field); 1428EXPORT_SYMBOL_GPL(snmp_fold_field);
1429 1429
1430#if BITS_PER_LONG==32
1431
1432u64 snmp_fold_field64(void __percpu *mib[], int offt, size_t syncp_offset)
1433{
1434 u64 res = 0;
1435 int cpu;
1436
1437 for_each_possible_cpu(cpu) {
1438 void *bhptr, *userptr;
1439 struct u64_stats_sync *syncp;
1440 u64 v_bh, v_user;
1441 unsigned int start;
1442
1443 /* first mib used by softirq context, we must use _bh() accessors */
1444 bhptr = per_cpu_ptr(SNMP_STAT_BHPTR(mib), cpu);
1445 syncp = (struct u64_stats_sync *)(bhptr + syncp_offset);
1446 do {
1447 start = u64_stats_fetch_begin_bh(syncp);
1448 v_bh = *(((u64 *) bhptr) + offt);
1449 } while (u64_stats_fetch_retry_bh(syncp, start));
1450
1451 /* second mib used in USER context */
1452 userptr = per_cpu_ptr(SNMP_STAT_USRPTR(mib), cpu);
1453 syncp = (struct u64_stats_sync *)(userptr + syncp_offset);
1454 do {
1455 start = u64_stats_fetch_begin(syncp);
1456 v_user = *(((u64 *) userptr) + offt);
1457 } while (u64_stats_fetch_retry(syncp, start));
1458
1459 res += v_bh + v_user;
1460 }
1461 return res;
1462}
1463EXPORT_SYMBOL_GPL(snmp_fold_field64);
1464#endif
1465
1430int snmp_mib_init(void __percpu *ptr[2], size_t mibsize, size_t align) 1466int snmp_mib_init(void __percpu *ptr[2], size_t mibsize, size_t align)
1431{ 1467{
1432 BUG_ON(ptr == NULL); 1468 BUG_ON(ptr == NULL);
diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c
index e320ca6b3ef3..4ae1f203f7cb 100644
--- a/net/ipv4/proc.c
+++ b/net/ipv4/proc.c
@@ -343,10 +343,12 @@ static int snmp_seq_show(struct seq_file *seq, void *v)
343 IPV4_DEVCONF_ALL(net, FORWARDING) ? 1 : 2, 343 IPV4_DEVCONF_ALL(net, FORWARDING) ? 1 : 2,
344 sysctl_ip_default_ttl); 344 sysctl_ip_default_ttl);
345 345
346 BUILD_BUG_ON(offsetof(struct ipstats_mib, mibs) != 0);
346 for (i = 0; snmp4_ipstats_list[i].name != NULL; i++) 347 for (i = 0; snmp4_ipstats_list[i].name != NULL; i++)
347 seq_printf(seq, " %lu", 348 seq_printf(seq, " %llu",
348 snmp_fold_field((void __percpu **)net->mib.ip_statistics, 349 snmp_fold_field64((void __percpu **)net->mib.ip_statistics,
349 snmp4_ipstats_list[i].entry)); 350 snmp4_ipstats_list[i].entry,
351 offsetof(struct ipstats_mib, syncp)));
350 352
351 icmp_put(seq); /* RFC 2011 compatibility */ 353 icmp_put(seq); /* RFC 2011 compatibility */
352 icmpmsg_put(seq); 354 icmpmsg_put(seq);
@@ -432,9 +434,10 @@ static int netstat_seq_show(struct seq_file *seq, void *v)
432 434
433 seq_puts(seq, "\nIpExt:"); 435 seq_puts(seq, "\nIpExt:");
434 for (i = 0; snmp4_ipextstats_list[i].name != NULL; i++) 436 for (i = 0; snmp4_ipextstats_list[i].name != NULL; i++)
435 seq_printf(seq, " %lu", 437 seq_printf(seq, " %llu",
436 snmp_fold_field((void __percpu **)net->mib.ip_statistics, 438 snmp_fold_field64((void __percpu **)net->mib.ip_statistics,
437 snmp4_ipextstats_list[i].entry)); 439 snmp4_ipextstats_list[i].entry,
440 offsetof(struct ipstats_mib, syncp)));
438 441
439 seq_putc(seq, '\n'); 442 seq_putc(seq, '\n');
440 return 0; 443 return 0;
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 2514adf5251e..e81155d2f251 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -3862,12 +3862,28 @@ static inline void __snmp6_fill_stats(u64 *stats, void __percpu **mib,
3862 memset(&stats[items], 0, pad); 3862 memset(&stats[items], 0, pad);
3863} 3863}
3864 3864
3865static inline void __snmp6_fill_stats64(u64 *stats, void __percpu **mib,
3866 int items, int bytes, size_t syncpoff)
3867{
3868 int i;
3869 int pad = bytes - sizeof(u64) * items;
3870 BUG_ON(pad < 0);
3871
3872 /* Use put_unaligned() because stats may not be aligned for u64. */
3873 put_unaligned(items, &stats[0]);
3874 for (i = 1; i < items; i++)
3875 put_unaligned(snmp_fold_field64(mib, i, syncpoff), &stats[i]);
3876
3877 memset(&stats[items], 0, pad);
3878}
3879
3865static void snmp6_fill_stats(u64 *stats, struct inet6_dev *idev, int attrtype, 3880static void snmp6_fill_stats(u64 *stats, struct inet6_dev *idev, int attrtype,
3866 int bytes) 3881 int bytes)
3867{ 3882{
3868 switch (attrtype) { 3883 switch (attrtype) {
3869 case IFLA_INET6_STATS: 3884 case IFLA_INET6_STATS:
3870 __snmp6_fill_stats(stats, (void __percpu **)idev->stats.ipv6, IPSTATS_MIB_MAX, bytes); 3885 __snmp6_fill_stats64(stats, (void __percpu **)idev->stats.ipv6,
3886 IPSTATS_MIB_MAX, bytes, offsetof(struct ipstats_mib, syncp));
3871 break; 3887 break;
3872 case IFLA_INET6_ICMP6STATS: 3888 case IFLA_INET6_ICMP6STATS:
3873 __snmp6_fill_stats(stats, (void __percpu **)idev->stats.icmpv6, ICMP6_MIB_MAX, bytes); 3889 __snmp6_fill_stats(stats, (void __percpu **)idev->stats.icmpv6, ICMP6_MIB_MAX, bytes);
diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c
index 566798d69f37..d082eaeefa25 100644
--- a/net/ipv6/proc.c
+++ b/net/ipv6/proc.c
@@ -174,17 +174,28 @@ static void snmp6_seq_show_item(struct seq_file *seq, void __percpu **mib,
174 const struct snmp_mib *itemlist) 174 const struct snmp_mib *itemlist)
175{ 175{
176 int i; 176 int i;
177 for (i=0; itemlist[i].name; i++) 177
178 for (i = 0; itemlist[i].name; i++)
178 seq_printf(seq, "%-32s\t%lu\n", itemlist[i].name, 179 seq_printf(seq, "%-32s\t%lu\n", itemlist[i].name,
179 snmp_fold_field(mib, itemlist[i].entry)); 180 snmp_fold_field(mib, itemlist[i].entry));
180} 181}
181 182
183static void snmp6_seq_show_item64(struct seq_file *seq, void __percpu **mib,
184 const struct snmp_mib *itemlist, size_t syncpoff)
185{
186 int i;
187
188 for (i = 0; itemlist[i].name; i++)
189 seq_printf(seq, "%-32s\t%llu\n", itemlist[i].name,
190 snmp_fold_field64(mib, itemlist[i].entry, syncpoff));
191}
192
182static int snmp6_seq_show(struct seq_file *seq, void *v) 193static int snmp6_seq_show(struct seq_file *seq, void *v)
183{ 194{
184 struct net *net = (struct net *)seq->private; 195 struct net *net = (struct net *)seq->private;
185 196
186 snmp6_seq_show_item(seq, (void __percpu **)net->mib.ipv6_statistics, 197 snmp6_seq_show_item64(seq, (void __percpu **)net->mib.ipv6_statistics,
187 snmp6_ipstats_list); 198 snmp6_ipstats_list, offsetof(struct ipstats_mib, syncp));
188 snmp6_seq_show_item(seq, (void __percpu **)net->mib.icmpv6_statistics, 199 snmp6_seq_show_item(seq, (void __percpu **)net->mib.icmpv6_statistics,
189 snmp6_icmp6_list); 200 snmp6_icmp6_list);
190 snmp6_seq_show_icmpv6msg(seq, 201 snmp6_seq_show_icmpv6msg(seq,