diff options
-rw-r--r-- | include/net/if_inet6.h | 4 | ||||
-rw-r--r-- | include/net/ipv6.h | 19 | ||||
-rw-r--r-- | include/net/snmp.h | 14 | ||||
-rw-r--r-- | net/ipv6/addrconf.c | 24 | ||||
-rw-r--r-- | net/ipv6/proc.c | 40 |
5 files changed, 68 insertions, 33 deletions
diff --git a/include/net/if_inet6.h b/include/net/if_inet6.h index 0c603fe65377..11cf373970a9 100644 --- a/include/net/if_inet6.h +++ b/include/net/if_inet6.h | |||
@@ -154,8 +154,8 @@ struct ifacaddr6 { | |||
154 | struct ipv6_devstat { | 154 | struct ipv6_devstat { |
155 | struct proc_dir_entry *proc_dir_entry; | 155 | struct proc_dir_entry *proc_dir_entry; |
156 | DEFINE_SNMP_STAT(struct ipstats_mib, ipv6); | 156 | DEFINE_SNMP_STAT(struct ipstats_mib, ipv6); |
157 | DEFINE_SNMP_STAT(struct icmpv6_mib, icmpv6); | 157 | DEFINE_SNMP_STAT_ATOMIC(struct icmpv6_mib_device, icmpv6dev); |
158 | DEFINE_SNMP_STAT(struct icmpv6msg_mib, icmpv6msg); | 158 | DEFINE_SNMP_STAT_ATOMIC(struct icmpv6msg_mib_device, icmpv6msgdev); |
159 | }; | 159 | }; |
160 | 160 | ||
161 | struct inet6_dev { | 161 | struct inet6_dev { |
diff --git a/include/net/ipv6.h b/include/net/ipv6.h index e1c60b43e73b..c033ed00df7d 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h | |||
@@ -123,6 +123,15 @@ extern struct ctl_path net_ipv6_ctl_path[]; | |||
123 | SNMP_INC_STATS##modifier((net)->mib.statname##_statistics, (field));\ | 123 | SNMP_INC_STATS##modifier((net)->mib.statname##_statistics, (field));\ |
124 | }) | 124 | }) |
125 | 125 | ||
126 | /* per device counters are atomic_long_t */ | ||
127 | #define _DEVINCATOMIC(net, statname, modifier, idev, field) \ | ||
128 | ({ \ | ||
129 | struct inet6_dev *_idev = (idev); \ | ||
130 | if (likely(_idev != NULL)) \ | ||
131 | SNMP_INC_STATS_ATOMIC_LONG((_idev)->stats.statname##dev, (field)); \ | ||
132 | SNMP_INC_STATS##modifier((net)->mib.statname##_statistics, (field));\ | ||
133 | }) | ||
134 | |||
126 | #define _DEVADD(net, statname, modifier, idev, field, val) \ | 135 | #define _DEVADD(net, statname, modifier, idev, field, val) \ |
127 | ({ \ | 136 | ({ \ |
128 | struct inet6_dev *_idev = (idev); \ | 137 | struct inet6_dev *_idev = (idev); \ |
@@ -154,16 +163,16 @@ extern struct ctl_path net_ipv6_ctl_path[]; | |||
154 | #define IP6_UPD_PO_STATS_BH(net, idev,field,val) \ | 163 | #define IP6_UPD_PO_STATS_BH(net, idev,field,val) \ |
155 | _DEVUPD(net, ipv6, 64_BH, idev, field, val) | 164 | _DEVUPD(net, ipv6, 64_BH, idev, field, val) |
156 | #define ICMP6_INC_STATS(net, idev, field) \ | 165 | #define ICMP6_INC_STATS(net, idev, field) \ |
157 | _DEVINC(net, icmpv6, , idev, field) | 166 | _DEVINCATOMIC(net, icmpv6, , idev, field) |
158 | #define ICMP6_INC_STATS_BH(net, idev, field) \ | 167 | #define ICMP6_INC_STATS_BH(net, idev, field) \ |
159 | _DEVINC(net, icmpv6, _BH, idev, field) | 168 | _DEVINCATOMIC(net, icmpv6, _BH, idev, field) |
160 | 169 | ||
161 | #define ICMP6MSGOUT_INC_STATS(net, idev, field) \ | 170 | #define ICMP6MSGOUT_INC_STATS(net, idev, field) \ |
162 | _DEVINC(net, icmpv6msg, , idev, field +256) | 171 | _DEVINCATOMIC(net, icmpv6msg, , idev, field +256) |
163 | #define ICMP6MSGOUT_INC_STATS_BH(net, idev, field) \ | 172 | #define ICMP6MSGOUT_INC_STATS_BH(net, idev, field) \ |
164 | _DEVINC(net, icmpv6msg, _BH, idev, field +256) | 173 | _DEVINCATOMIC(net, icmpv6msg, _BH, idev, field +256) |
165 | #define ICMP6MSGIN_INC_STATS_BH(net, idev, field) \ | 174 | #define ICMP6MSGIN_INC_STATS_BH(net, idev, field) \ |
166 | _DEVINC(net, icmpv6msg, _BH, idev, field) | 175 | _DEVINCATOMIC(net, icmpv6msg, _BH, idev, field) |
167 | 176 | ||
168 | struct ip6_ra_chain { | 177 | struct ip6_ra_chain { |
169 | struct ip6_ra_chain *next; | 178 | struct ip6_ra_chain *next; |
diff --git a/include/net/snmp.h b/include/net/snmp.h index 27461d6dd46f..479083a78b0c 100644 --- a/include/net/snmp.h +++ b/include/net/snmp.h | |||
@@ -72,14 +72,24 @@ struct icmpmsg_mib { | |||
72 | 72 | ||
73 | /* ICMP6 (IPv6-ICMP) */ | 73 | /* ICMP6 (IPv6-ICMP) */ |
74 | #define ICMP6_MIB_MAX __ICMP6_MIB_MAX | 74 | #define ICMP6_MIB_MAX __ICMP6_MIB_MAX |
75 | /* per network ns counters */ | ||
75 | struct icmpv6_mib { | 76 | struct icmpv6_mib { |
76 | unsigned long mibs[ICMP6_MIB_MAX]; | 77 | unsigned long mibs[ICMP6_MIB_MAX]; |
77 | }; | 78 | }; |
79 | /* per device counters, (shared on all cpus) */ | ||
80 | struct icmpv6_mib_device { | ||
81 | atomic_long_t mibs[ICMP6_MIB_MAX]; | ||
82 | }; | ||
78 | 83 | ||
79 | #define ICMP6MSG_MIB_MAX __ICMP6MSG_MIB_MAX | 84 | #define ICMP6MSG_MIB_MAX __ICMP6MSG_MIB_MAX |
85 | /* per network ns counters */ | ||
80 | struct icmpv6msg_mib { | 86 | struct icmpv6msg_mib { |
81 | unsigned long mibs[ICMP6MSG_MIB_MAX]; | 87 | unsigned long mibs[ICMP6MSG_MIB_MAX]; |
82 | }; | 88 | }; |
89 | /* per device counters, (shared on all cpus) */ | ||
90 | struct icmpv6msg_mib_device { | ||
91 | atomic_long_t mibs[ICMP6MSG_MIB_MAX]; | ||
92 | }; | ||
83 | 93 | ||
84 | 94 | ||
85 | /* TCP */ | 95 | /* TCP */ |
@@ -114,6 +124,8 @@ struct linux_xfrm_mib { | |||
114 | */ | 124 | */ |
115 | #define DEFINE_SNMP_STAT(type, name) \ | 125 | #define DEFINE_SNMP_STAT(type, name) \ |
116 | __typeof__(type) __percpu *name[2] | 126 | __typeof__(type) __percpu *name[2] |
127 | #define DEFINE_SNMP_STAT_ATOMIC(type, name) \ | ||
128 | __typeof__(type) *name | ||
117 | #define DECLARE_SNMP_STAT(type, name) \ | 129 | #define DECLARE_SNMP_STAT(type, name) \ |
118 | extern __typeof__(type) __percpu *name[2] | 130 | extern __typeof__(type) __percpu *name[2] |
119 | 131 | ||
@@ -124,6 +136,8 @@ struct linux_xfrm_mib { | |||
124 | __this_cpu_inc(mib[0]->mibs[field]) | 136 | __this_cpu_inc(mib[0]->mibs[field]) |
125 | #define SNMP_INC_STATS_USER(mib, field) \ | 137 | #define SNMP_INC_STATS_USER(mib, field) \ |
126 | this_cpu_inc(mib[1]->mibs[field]) | 138 | this_cpu_inc(mib[1]->mibs[field]) |
139 | #define SNMP_INC_STATS_ATOMIC_LONG(mib, field) \ | ||
140 | atomic_long_inc(&mib->mibs[field]) | ||
127 | #define SNMP_INC_STATS(mib, field) \ | 141 | #define SNMP_INC_STATS(mib, field) \ |
128 | this_cpu_inc(mib[!in_softirq()]->mibs[field]) | 142 | this_cpu_inc(mib[!in_softirq()]->mibs[field]) |
129 | #define SNMP_DEC_STATS(mib, field) \ | 143 | #define SNMP_DEC_STATS(mib, field) \ |
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index f2f9b2e3cfe9..3cfbbf3387a0 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -289,19 +289,19 @@ static int snmp6_alloc_dev(struct inet6_dev *idev) | |||
289 | sizeof(struct ipstats_mib), | 289 | sizeof(struct ipstats_mib), |
290 | __alignof__(struct ipstats_mib)) < 0) | 290 | __alignof__(struct ipstats_mib)) < 0) |
291 | goto err_ip; | 291 | goto err_ip; |
292 | if (snmp_mib_init((void __percpu **)idev->stats.icmpv6, | 292 | idev->stats.icmpv6dev = kzalloc(sizeof(struct icmpv6_mib_device), |
293 | sizeof(struct icmpv6_mib), | 293 | GFP_KERNEL); |
294 | __alignof__(struct icmpv6_mib)) < 0) | 294 | if (!idev->stats.icmpv6dev) |
295 | goto err_icmp; | 295 | goto err_icmp; |
296 | if (snmp_mib_init((void __percpu **)idev->stats.icmpv6msg, | 296 | idev->stats.icmpv6msgdev = kzalloc(sizeof(struct icmpv6msg_mib_device), |
297 | sizeof(struct icmpv6msg_mib), | 297 | GFP_KERNEL); |
298 | __alignof__(struct icmpv6msg_mib)) < 0) | 298 | if (!idev->stats.icmpv6msgdev) |
299 | goto err_icmpmsg; | 299 | goto err_icmpmsg; |
300 | 300 | ||
301 | return 0; | 301 | return 0; |
302 | 302 | ||
303 | err_icmpmsg: | 303 | err_icmpmsg: |
304 | snmp_mib_free((void __percpu **)idev->stats.icmpv6); | 304 | kfree(idev->stats.icmpv6dev); |
305 | err_icmp: | 305 | err_icmp: |
306 | snmp_mib_free((void __percpu **)idev->stats.ipv6); | 306 | snmp_mib_free((void __percpu **)idev->stats.ipv6); |
307 | err_ip: | 307 | err_ip: |
@@ -310,8 +310,8 @@ err_ip: | |||
310 | 310 | ||
311 | static void snmp6_free_dev(struct inet6_dev *idev) | 311 | static void snmp6_free_dev(struct inet6_dev *idev) |
312 | { | 312 | { |
313 | snmp_mib_free((void __percpu **)idev->stats.icmpv6msg); | 313 | kfree(idev->stats.icmpv6msgdev); |
314 | snmp_mib_free((void __percpu **)idev->stats.icmpv6); | 314 | kfree(idev->stats.icmpv6dev); |
315 | snmp_mib_free((void __percpu **)idev->stats.ipv6); | 315 | snmp_mib_free((void __percpu **)idev->stats.ipv6); |
316 | } | 316 | } |
317 | 317 | ||
@@ -3838,7 +3838,7 @@ static inline size_t inet6_if_nlmsg_size(void) | |||
3838 | + nla_total_size(inet6_ifla6_size()); /* IFLA_PROTINFO */ | 3838 | + nla_total_size(inet6_ifla6_size()); /* IFLA_PROTINFO */ |
3839 | } | 3839 | } |
3840 | 3840 | ||
3841 | static inline void __snmp6_fill_stats(u64 *stats, void __percpu **mib, | 3841 | static inline void __snmp6_fill_statsdev(u64 *stats, atomic_long_t *mib, |
3842 | int items, int bytes) | 3842 | int items, int bytes) |
3843 | { | 3843 | { |
3844 | int i; | 3844 | int i; |
@@ -3848,7 +3848,7 @@ static inline void __snmp6_fill_stats(u64 *stats, void __percpu **mib, | |||
3848 | /* Use put_unaligned() because stats may not be aligned for u64. */ | 3848 | /* Use put_unaligned() because stats may not be aligned for u64. */ |
3849 | put_unaligned(items, &stats[0]); | 3849 | put_unaligned(items, &stats[0]); |
3850 | for (i = 1; i < items; i++) | 3850 | for (i = 1; i < items; i++) |
3851 | put_unaligned(snmp_fold_field(mib, i), &stats[i]); | 3851 | put_unaligned(atomic_long_read(&mib[i]), &stats[i]); |
3852 | 3852 | ||
3853 | memset(&stats[items], 0, pad); | 3853 | memset(&stats[items], 0, pad); |
3854 | } | 3854 | } |
@@ -3877,7 +3877,7 @@ static void snmp6_fill_stats(u64 *stats, struct inet6_dev *idev, int attrtype, | |||
3877 | IPSTATS_MIB_MAX, bytes, offsetof(struct ipstats_mib, syncp)); | 3877 | IPSTATS_MIB_MAX, bytes, offsetof(struct ipstats_mib, syncp)); |
3878 | break; | 3878 | break; |
3879 | case IFLA_INET6_ICMP6STATS: | 3879 | case IFLA_INET6_ICMP6STATS: |
3880 | __snmp6_fill_stats(stats, (void __percpu **)idev->stats.icmpv6, ICMP6_MIB_MAX, bytes); | 3880 | __snmp6_fill_statsdev(stats, idev->stats.icmpv6dev->mibs, ICMP6_MIB_MAX, bytes); |
3881 | break; | 3881 | break; |
3882 | } | 3882 | } |
3883 | } | 3883 | } |
diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index 24b3558b8e67..18ff5df7ec02 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c | |||
@@ -141,7 +141,11 @@ static const struct snmp_mib snmp6_udplite6_list[] = { | |||
141 | SNMP_MIB_SENTINEL | 141 | SNMP_MIB_SENTINEL |
142 | }; | 142 | }; |
143 | 143 | ||
144 | static void snmp6_seq_show_icmpv6msg(struct seq_file *seq, void __percpu **mib) | 144 | /* can be called either with percpu mib (pcpumib != NULL), |
145 | * or shared one (smib != NULL) | ||
146 | */ | ||
147 | static void snmp6_seq_show_icmpv6msg(struct seq_file *seq, void __percpu **pcpumib, | ||
148 | atomic_long_t *smib) | ||
145 | { | 149 | { |
146 | char name[32]; | 150 | char name[32]; |
147 | int i; | 151 | int i; |
@@ -158,14 +162,14 @@ static void snmp6_seq_show_icmpv6msg(struct seq_file *seq, void __percpu **mib) | |||
158 | snprintf(name, sizeof(name), "Icmp6%s%s", | 162 | snprintf(name, sizeof(name), "Icmp6%s%s", |
159 | i & 0x100 ? "Out" : "In", p); | 163 | i & 0x100 ? "Out" : "In", p); |
160 | seq_printf(seq, "%-32s\t%lu\n", name, | 164 | seq_printf(seq, "%-32s\t%lu\n", name, |
161 | snmp_fold_field(mib, i)); | 165 | pcpumib ? snmp_fold_field(pcpumib, i) : atomic_long_read(smib + i)); |
162 | } | 166 | } |
163 | 167 | ||
164 | /* print by number (nonzero only) - ICMPMsgStat format */ | 168 | /* print by number (nonzero only) - ICMPMsgStat format */ |
165 | for (i = 0; i < ICMP6MSG_MIB_MAX; i++) { | 169 | for (i = 0; i < ICMP6MSG_MIB_MAX; i++) { |
166 | unsigned long val; | 170 | unsigned long val; |
167 | 171 | ||
168 | val = snmp_fold_field(mib, i); | 172 | val = pcpumib ? snmp_fold_field(pcpumib, i) : atomic_long_read(smib + i); |
169 | if (!val) | 173 | if (!val) |
170 | continue; | 174 | continue; |
171 | snprintf(name, sizeof(name), "Icmp6%sType%u", | 175 | snprintf(name, sizeof(name), "Icmp6%sType%u", |
@@ -174,14 +178,22 @@ static void snmp6_seq_show_icmpv6msg(struct seq_file *seq, void __percpu **mib) | |||
174 | } | 178 | } |
175 | } | 179 | } |
176 | 180 | ||
177 | static void snmp6_seq_show_item(struct seq_file *seq, void __percpu **mib, | 181 | /* can be called either with percpu mib (pcpumib != NULL), |
182 | * or shared one (smib != NULL) | ||
183 | */ | ||
184 | static void snmp6_seq_show_item(struct seq_file *seq, void __percpu **pcpumib, | ||
185 | atomic_long_t *smib, | ||
178 | const struct snmp_mib *itemlist) | 186 | const struct snmp_mib *itemlist) |
179 | { | 187 | { |
180 | int i; | 188 | int i; |
189 | unsigned long val; | ||
181 | 190 | ||
182 | for (i = 0; itemlist[i].name; i++) | 191 | for (i = 0; itemlist[i].name; i++) { |
183 | seq_printf(seq, "%-32s\t%lu\n", itemlist[i].name, | 192 | val = pcpumib ? |
184 | snmp_fold_field(mib, itemlist[i].entry)); | 193 | snmp_fold_field(pcpumib, itemlist[i].entry) : |
194 | atomic_long_read(smib + itemlist[i].entry); | ||
195 | seq_printf(seq, "%-32s\t%lu\n", itemlist[i].name, val); | ||
196 | } | ||
185 | } | 197 | } |
186 | 198 | ||
187 | static void snmp6_seq_show_item64(struct seq_file *seq, void __percpu **mib, | 199 | static void snmp6_seq_show_item64(struct seq_file *seq, void __percpu **mib, |
@@ -201,13 +213,13 @@ static int snmp6_seq_show(struct seq_file *seq, void *v) | |||
201 | snmp6_seq_show_item64(seq, (void __percpu **)net->mib.ipv6_statistics, | 213 | snmp6_seq_show_item64(seq, (void __percpu **)net->mib.ipv6_statistics, |
202 | snmp6_ipstats_list, offsetof(struct ipstats_mib, syncp)); | 214 | snmp6_ipstats_list, offsetof(struct ipstats_mib, syncp)); |
203 | snmp6_seq_show_item(seq, (void __percpu **)net->mib.icmpv6_statistics, | 215 | snmp6_seq_show_item(seq, (void __percpu **)net->mib.icmpv6_statistics, |
204 | snmp6_icmp6_list); | 216 | NULL, snmp6_icmp6_list); |
205 | snmp6_seq_show_icmpv6msg(seq, | 217 | snmp6_seq_show_icmpv6msg(seq, |
206 | (void __percpu **)net->mib.icmpv6msg_statistics); | 218 | (void __percpu **)net->mib.icmpv6msg_statistics, NULL); |
207 | snmp6_seq_show_item(seq, (void __percpu **)net->mib.udp_stats_in6, | 219 | snmp6_seq_show_item(seq, (void __percpu **)net->mib.udp_stats_in6, |
208 | snmp6_udp6_list); | 220 | NULL, snmp6_udp6_list); |
209 | snmp6_seq_show_item(seq, (void __percpu **)net->mib.udplite_stats_in6, | 221 | snmp6_seq_show_item(seq, (void __percpu **)net->mib.udplite_stats_in6, |
210 | snmp6_udplite6_list); | 222 | NULL, snmp6_udplite6_list); |
211 | return 0; | 223 | return 0; |
212 | } | 224 | } |
213 | 225 | ||
@@ -229,11 +241,11 @@ static int snmp6_dev_seq_show(struct seq_file *seq, void *v) | |||
229 | struct inet6_dev *idev = (struct inet6_dev *)seq->private; | 241 | struct inet6_dev *idev = (struct inet6_dev *)seq->private; |
230 | 242 | ||
231 | seq_printf(seq, "%-32s\t%u\n", "ifIndex", idev->dev->ifindex); | 243 | seq_printf(seq, "%-32s\t%u\n", "ifIndex", idev->dev->ifindex); |
232 | snmp6_seq_show_item(seq, (void __percpu **)idev->stats.ipv6, | 244 | snmp6_seq_show_item(seq, (void __percpu **)idev->stats.ipv6, NULL, |
233 | snmp6_ipstats_list); | 245 | snmp6_ipstats_list); |
234 | snmp6_seq_show_item(seq, (void __percpu **)idev->stats.icmpv6, | 246 | snmp6_seq_show_item(seq, NULL, idev->stats.icmpv6dev->mibs, |
235 | snmp6_icmp6_list); | 247 | snmp6_icmp6_list); |
236 | snmp6_seq_show_icmpv6msg(seq, (void __percpu **)idev->stats.icmpv6msg); | 248 | snmp6_seq_show_icmpv6msg(seq, NULL, idev->stats.icmpv6msgdev->mibs); |
237 | return 0; | 249 | return 0; |
238 | } | 250 | } |
239 | 251 | ||