Blame view
net/core/gen_stats.c
10.5 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
/* * net/core/gen_stats.c * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * * Authors: Thomas Graf <tgraf@suug.ch> * Jamal Hadi Salim * Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> * * See Documentation/networking/gen_stats.txt */ #include <linux/types.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/interrupt.h> #include <linux/socket.h> #include <linux/rtnetlink.h> #include <linux/gen_stats.h> |
1e90474c3 [NET_SCHED]: Conv... |
23 |
#include <net/netlink.h> |
1da177e4c Linux-2.6.12-rc2 |
24 25 26 27 |
#include <net/gen_stats.h> static inline int |
9854518ea sched: align nlat... |
28 |
gnet_stats_copy(struct gnet_dump *d, int type, void *buf, int size, int padattr) |
1da177e4c Linux-2.6.12-rc2 |
29 |
{ |
9854518ea sched: align nlat... |
30 |
if (nla_put_64bit(d->skb, type, size, buf, padattr)) |
14ad6647f gen_stats: Stop u... |
31 |
goto nla_put_failure; |
1da177e4c Linux-2.6.12-rc2 |
32 |
return 0; |
1e90474c3 [NET_SCHED]: Conv... |
33 |
nla_put_failure: |
edb09eb17 net: sched: do no... |
34 35 |
if (d->lock) spin_unlock_bh(d->lock); |
1c4cff0cf gen_stats.c: Dupl... |
36 37 38 |
kfree(d->xstats); d->xstats = NULL; d->xstats_len = 0; |
1da177e4c Linux-2.6.12-rc2 |
39 40 41 42 43 44 45 46 47 48 49 |
return -1; } /** * gnet_stats_start_copy_compat - start dumping procedure in compatibility mode * @skb: socket buffer to put statistics TLVs into * @type: TLV type for top level statistic TLV * @tc_stats_type: TLV type for backward compatibility struct tc_stats TLV * @xstats_type: TLV type for backward compatibility xstats TLV * @lock: statistics lock * @d: dumping handle |
e0d194adf net_sched: add mi... |
50 |
* @padattr: padding attribute |
1da177e4c Linux-2.6.12-rc2 |
51 52 53 54 55 56 57 58 59 60 61 62 |
* * Initializes the dumping handle, grabs the statistic lock and appends * an empty TLV header to the socket buffer for use a container for all * other statistic TLVS. * * The dumping handle is marked to be in backward compatibility mode telling * all gnet_stats_copy_XXX() functions to fill a local copy of struct tc_stats. * * Returns 0 on success or -1 if the room in the socket buffer was not sufficient. */ int gnet_stats_start_copy_compat(struct sk_buff *skb, int type, int tc_stats_type, |
9854518ea sched: align nlat... |
63 64 |
int xstats_type, spinlock_t *lock, struct gnet_dump *d, int padattr) |
9a429c498 [NET]: Add some a... |
65 |
__acquires(lock) |
1da177e4c Linux-2.6.12-rc2 |
66 67 |
{ memset(d, 0, sizeof(*d)); |
4ec93edb1 [NET] CORE: Fix w... |
68 |
|
1da177e4c Linux-2.6.12-rc2 |
69 |
if (type) |
1e90474c3 [NET_SCHED]: Conv... |
70 |
d->tail = (struct nlattr *)skb_tail_pointer(skb); |
1da177e4c Linux-2.6.12-rc2 |
71 72 73 |
d->skb = skb; d->compat_tc_stats = tc_stats_type; d->compat_xstats = xstats_type; |
9854518ea sched: align nlat... |
74 |
d->padattr = padattr; |
edb09eb17 net: sched: do no... |
75 76 77 78 |
if (lock) { d->lock = lock; spin_lock_bh(lock); } |
c8347d91c gen_stats: Fix ne... |
79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
if (d->tail) { int ret = gnet_stats_copy(d, type, NULL, 0, padattr); /* The initial attribute added in gnet_stats_copy() may be * preceded by a padding attribute, in which case d->tail will * end up pointing at the padding instead of the real attribute. * Fix this so gnet_stats_finish_copy() adjusts the length of * the right attribute. */ if (ret == 0 && d->tail->nla_type == padattr) d->tail = (struct nlattr *)((char *)d->tail + NLA_ALIGN(d->tail->nla_len)); return ret; } |
1da177e4c Linux-2.6.12-rc2 |
93 94 95 |
return 0; } |
9e34a5b51 net/core: EXPORT_... |
96 |
EXPORT_SYMBOL(gnet_stats_start_copy_compat); |
1da177e4c Linux-2.6.12-rc2 |
97 98 |
/** |
9854518ea sched: align nlat... |
99 |
* gnet_stats_start_copy - start dumping procedure in compatibility mode |
1da177e4c Linux-2.6.12-rc2 |
100 101 102 103 |
* @skb: socket buffer to put statistics TLVs into * @type: TLV type for top level statistic TLV * @lock: statistics lock * @d: dumping handle |
e0d194adf net_sched: add mi... |
104 |
* @padattr: padding attribute |
1da177e4c Linux-2.6.12-rc2 |
105 106 107 108 109 110 111 112 113 |
* * Initializes the dumping handle, grabs the statistic lock and appends * an empty TLV header to the socket buffer for use a container for all * other statistic TLVS. * * Returns 0 on success or -1 if the room in the socket buffer was not sufficient. */ int gnet_stats_start_copy(struct sk_buff *skb, int type, spinlock_t *lock, |
9854518ea sched: align nlat... |
114 |
struct gnet_dump *d, int padattr) |
1da177e4c Linux-2.6.12-rc2 |
115 |
{ |
9854518ea sched: align nlat... |
116 |
return gnet_stats_start_copy_compat(skb, type, 0, 0, lock, d, padattr); |
1da177e4c Linux-2.6.12-rc2 |
117 |
} |
9e34a5b51 net/core: EXPORT_... |
118 |
EXPORT_SYMBOL(gnet_stats_start_copy); |
1da177e4c Linux-2.6.12-rc2 |
119 |
|
22e0f8b93 net: sched: make ... |
120 121 122 123 124 125 126 127 128 |
static void __gnet_stats_copy_basic_cpu(struct gnet_stats_basic_packed *bstats, struct gnet_stats_basic_cpu __percpu *cpu) { int i; for_each_possible_cpu(i) { struct gnet_stats_basic_cpu *bcpu = per_cpu_ptr(cpu, i); unsigned int start; |
02c0fc1b8 net_sched: fix un... |
129 130 |
u64 bytes; u32 packets; |
22e0f8b93 net: sched: make ... |
131 132 133 134 135 136 |
do { start = u64_stats_fetch_begin_irq(&bcpu->syncp); bytes = bcpu->bstats.bytes; packets = bcpu->bstats.packets; } while (u64_stats_fetch_retry_irq(&bcpu->syncp, start)); |
02c0fc1b8 net_sched: fix un... |
137 138 |
bstats->bytes += bytes; bstats->packets += packets; |
22e0f8b93 net: sched: make ... |
139 140 141 142 |
} } void |
edb09eb17 net: sched: do no... |
143 144 |
__gnet_stats_copy_basic(const seqcount_t *running, struct gnet_stats_basic_packed *bstats, |
22e0f8b93 net: sched: make ... |
145 146 147 |
struct gnet_stats_basic_cpu __percpu *cpu, struct gnet_stats_basic_packed *b) { |
edb09eb17 net: sched: do no... |
148 |
unsigned int seq; |
22e0f8b93 net: sched: make ... |
149 150 |
if (cpu) { __gnet_stats_copy_basic_cpu(bstats, cpu); |
edb09eb17 net: sched: do no... |
151 152 153 154 155 |
return; } do { if (running) seq = read_seqcount_begin(running); |
22e0f8b93 net: sched: make ... |
156 157 |
bstats->bytes = b->bytes; bstats->packets = b->packets; |
edb09eb17 net: sched: do no... |
158 |
} while (running && read_seqcount_retry(running, seq)); |
22e0f8b93 net: sched: make ... |
159 160 |
} EXPORT_SYMBOL(__gnet_stats_copy_basic); |
1da177e4c Linux-2.6.12-rc2 |
161 162 |
/** * gnet_stats_copy_basic - copy basic statistics into statistic TLV |
123b36526 net: sched: fix m... |
163 |
* @running: seqcount_t pointer |
1da177e4c Linux-2.6.12-rc2 |
164 |
* @d: dumping handle |
b002fdcc8 gen_stats.c: Add ... |
165 |
* @cpu: copy statistic per cpu |
1da177e4c Linux-2.6.12-rc2 |
166 167 168 169 170 171 172 173 174 |
* @b: basic statistics * * Appends the basic statistics to the top level TLV created by * gnet_stats_start_copy(). * * Returns 0 on success or -1 with the statistic lock released * if the room in the socket buffer was not sufficient. */ int |
edb09eb17 net: sched: do no... |
175 176 |
gnet_stats_copy_basic(const seqcount_t *running, struct gnet_dump *d, |
22e0f8b93 net: sched: make ... |
177 178 |
struct gnet_stats_basic_cpu __percpu *cpu, struct gnet_stats_basic_packed *b) |
1da177e4c Linux-2.6.12-rc2 |
179 |
{ |
22e0f8b93 net: sched: make ... |
180 |
struct gnet_stats_basic_packed bstats = {0}; |
edb09eb17 net: sched: do no... |
181 |
__gnet_stats_copy_basic(running, &bstats, cpu, b); |
22e0f8b93 net: sched: make ... |
182 |
|
1da177e4c Linux-2.6.12-rc2 |
183 |
if (d->compat_tc_stats) { |
22e0f8b93 net: sched: make ... |
184 185 |
d->tc_stats.bytes = bstats.bytes; d->tc_stats.packets = bstats.packets; |
1da177e4c Linux-2.6.12-rc2 |
186 |
} |
c1a8f1f1c net: restore gnet... |
187 188 |
if (d->tail) { struct gnet_stats_basic sb; |
1da177e4c Linux-2.6.12-rc2 |
189 |
|
c1a8f1f1c net: restore gnet... |
190 |
memset(&sb, 0, sizeof(sb)); |
22e0f8b93 net: sched: make ... |
191 192 |
sb.bytes = bstats.bytes; sb.packets = bstats.packets; |
9854518ea sched: align nlat... |
193 194 |
return gnet_stats_copy(d, TCA_STATS_BASIC, &sb, sizeof(sb), TCA_STATS_PAD); |
c1a8f1f1c net: restore gnet... |
195 |
} |
1da177e4c Linux-2.6.12-rc2 |
196 197 |
return 0; } |
9e34a5b51 net/core: EXPORT_... |
198 |
EXPORT_SYMBOL(gnet_stats_copy_basic); |
1da177e4c Linux-2.6.12-rc2 |
199 200 201 202 |
/** * gnet_stats_copy_rate_est - copy rate estimator statistics into statistics TLV * @d: dumping handle |
1c0d32fde net_sched: gen_es... |
203 |
* @rate_est: rate estimator |
1da177e4c Linux-2.6.12-rc2 |
204 205 206 207 208 209 210 211 |
* * Appends the rate estimator statistics to the top level TLV created by * gnet_stats_start_copy(). * * Returns 0 on success or -1 with the statistic lock released * if the room in the socket buffer was not sufficient. */ int |
d250a5f90 pkt_sched: gen_es... |
212 |
gnet_stats_copy_rate_est(struct gnet_dump *d, |
1c0d32fde net_sched: gen_es... |
213 |
struct net_rate_estimator __rcu **rate_est) |
1da177e4c Linux-2.6.12-rc2 |
214 |
{ |
1c0d32fde net_sched: gen_es... |
215 |
struct gnet_stats_rate_est64 sample; |
45203a3b3 net_sched: add 64... |
216 217 |
struct gnet_stats_rate_est est; int res; |
1c0d32fde net_sched: gen_es... |
218 |
if (!gen_estimator_read(rate_est, &sample)) |
d250a5f90 pkt_sched: gen_es... |
219 |
return 0; |
1c0d32fde net_sched: gen_es... |
220 |
est.bps = min_t(u64, UINT_MAX, sample.bps); |
45203a3b3 net_sched: add 64... |
221 |
/* we have some time before reaching 2^32 packets per second */ |
1c0d32fde net_sched: gen_es... |
222 |
est.pps = sample.pps; |
45203a3b3 net_sched: add 64... |
223 |
|
1da177e4c Linux-2.6.12-rc2 |
224 |
if (d->compat_tc_stats) { |
45203a3b3 net_sched: add 64... |
225 226 |
d->tc_stats.bps = est.bps; d->tc_stats.pps = est.pps; |
1da177e4c Linux-2.6.12-rc2 |
227 |
} |
45203a3b3 net_sched: add 64... |
228 |
if (d->tail) { |
9854518ea sched: align nlat... |
229 230 |
res = gnet_stats_copy(d, TCA_STATS_RATE_EST, &est, sizeof(est), TCA_STATS_PAD); |
1c0d32fde net_sched: gen_es... |
231 |
if (res < 0 || est.bps == sample.bps) |
45203a3b3 net_sched: add 64... |
232 233 |
return res; /* emit 64bit stats only if needed */ |
1c0d32fde net_sched: gen_es... |
234 235 |
return gnet_stats_copy(d, TCA_STATS_RATE_EST64, &sample, sizeof(sample), TCA_STATS_PAD); |
45203a3b3 net_sched: add 64... |
236 |
} |
1da177e4c Linux-2.6.12-rc2 |
237 238 239 |
return 0; } |
9e34a5b51 net/core: EXPORT_... |
240 |
EXPORT_SYMBOL(gnet_stats_copy_rate_est); |
1da177e4c Linux-2.6.12-rc2 |
241 |
|
b0ab6f927 net: sched: enabl... |
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 |
static void __gnet_stats_copy_queue_cpu(struct gnet_stats_queue *qstats, const struct gnet_stats_queue __percpu *q) { int i; for_each_possible_cpu(i) { const struct gnet_stats_queue *qcpu = per_cpu_ptr(q, i); qstats->qlen = 0; qstats->backlog += qcpu->backlog; qstats->drops += qcpu->drops; qstats->requeues += qcpu->requeues; qstats->overlimits += qcpu->overlimits; } } static void __gnet_stats_copy_queue(struct gnet_stats_queue *qstats, const struct gnet_stats_queue __percpu *cpu, const struct gnet_stats_queue *q, __u32 qlen) { if (cpu) { __gnet_stats_copy_queue_cpu(qstats, cpu); } else { qstats->qlen = q->qlen; qstats->backlog = q->backlog; qstats->drops = q->drops; qstats->requeues = q->requeues; qstats->overlimits = q->overlimits; } qstats->qlen = qlen; } |
1da177e4c Linux-2.6.12-rc2 |
276 277 278 |
/** * gnet_stats_copy_queue - copy queue statistics into statistics TLV * @d: dumping handle |
b0ab6f927 net: sched: enabl... |
279 |
* @cpu_q: per cpu queue statistics |
1da177e4c Linux-2.6.12-rc2 |
280 |
* @q: queue statistics |
640158536 net: sched: restr... |
281 |
* @qlen: queue length statistics |
1da177e4c Linux-2.6.12-rc2 |
282 283 |
* * Appends the queue statistics to the top level TLV created by |
b0ab6f927 net: sched: enabl... |
284 285 |
* gnet_stats_start_copy(). Using per cpu queue statistics if * they are available. |
1da177e4c Linux-2.6.12-rc2 |
286 287 288 289 290 |
* * Returns 0 on success or -1 with the statistic lock released * if the room in the socket buffer was not sufficient. */ int |
640158536 net: sched: restr... |
291 |
gnet_stats_copy_queue(struct gnet_dump *d, |
b0ab6f927 net: sched: enabl... |
292 |
struct gnet_stats_queue __percpu *cpu_q, |
640158536 net: sched: restr... |
293 |
struct gnet_stats_queue *q, __u32 qlen) |
1da177e4c Linux-2.6.12-rc2 |
294 |
{ |
b0ab6f927 net: sched: enabl... |
295 296 297 |
struct gnet_stats_queue qstats = {0}; __gnet_stats_copy_queue(&qstats, cpu_q, q, qlen); |
640158536 net: sched: restr... |
298 |
|
1da177e4c Linux-2.6.12-rc2 |
299 |
if (d->compat_tc_stats) { |
b0ab6f927 net: sched: enabl... |
300 301 302 303 |
d->tc_stats.drops = qstats.drops; d->tc_stats.qlen = qstats.qlen; d->tc_stats.backlog = qstats.backlog; d->tc_stats.overlimits = qstats.overlimits; |
1da177e4c Linux-2.6.12-rc2 |
304 305 306 |
} if (d->tail) |
b0ab6f927 net: sched: enabl... |
307 |
return gnet_stats_copy(d, TCA_STATS_QUEUE, |
9854518ea sched: align nlat... |
308 309 |
&qstats, sizeof(qstats), TCA_STATS_PAD); |
1da177e4c Linux-2.6.12-rc2 |
310 311 312 |
return 0; } |
9e34a5b51 net/core: EXPORT_... |
313 |
EXPORT_SYMBOL(gnet_stats_copy_queue); |
1da177e4c Linux-2.6.12-rc2 |
314 315 316 317 318 319 320 |
/** * gnet_stats_copy_app - copy application specific statistics into statistics TLV * @d: dumping handle * @st: application specific statistics data * @len: length of data * |
e793c0f70 net: treewide: Fi... |
321 |
* Appends the application specific statistics to the top level TLV created by |
1da177e4c Linux-2.6.12-rc2 |
322 323 324 325 326 327 328 329 330 331 |
* gnet_stats_start_copy() and remembers the data for XSTATS if the dumping * handle is in backward compatibility mode. * * Returns 0 on success or -1 with the statistic lock released * if the room in the socket buffer was not sufficient. */ int gnet_stats_copy_app(struct gnet_dump *d, void *st, int len) { if (d->compat_xstats) { |
1c4cff0cf gen_stats.c: Dupl... |
332 333 334 |
d->xstats = kmemdup(st, len, GFP_ATOMIC); if (!d->xstats) goto err_out; |
1da177e4c Linux-2.6.12-rc2 |
335 336 337 338 |
d->xstats_len = len; } if (d->tail) |
9854518ea sched: align nlat... |
339 340 |
return gnet_stats_copy(d, TCA_STATS_APP, st, len, TCA_STATS_PAD); |
1da177e4c Linux-2.6.12-rc2 |
341 342 |
return 0; |
1c4cff0cf gen_stats.c: Dupl... |
343 344 |
err_out: |
edb09eb17 net: sched: do no... |
345 346 |
if (d->lock) spin_unlock_bh(d->lock); |
1c4cff0cf gen_stats.c: Dupl... |
347 |
d->xstats_len = 0; |
1c4cff0cf gen_stats.c: Dupl... |
348 |
return -1; |
1da177e4c Linux-2.6.12-rc2 |
349 |
} |
9e34a5b51 net/core: EXPORT_... |
350 |
EXPORT_SYMBOL(gnet_stats_copy_app); |
1da177e4c Linux-2.6.12-rc2 |
351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 |
/** * gnet_stats_finish_copy - finish dumping procedure * @d: dumping handle * * Corrects the length of the top level TLV to include all TLVs added * by gnet_stats_copy_XXX() calls. Adds the backward compatibility TLVs * if gnet_stats_start_copy_compat() was used and releases the statistics * lock. * * Returns 0 on success or -1 with the statistic lock released * if the room in the socket buffer was not sufficient. */ int gnet_stats_finish_copy(struct gnet_dump *d) { if (d->tail) |
1e90474c3 [NET_SCHED]: Conv... |
368 |
d->tail->nla_len = skb_tail_pointer(d->skb) - (u8 *)d->tail; |
1da177e4c Linux-2.6.12-rc2 |
369 370 371 |
if (d->compat_tc_stats) if (gnet_stats_copy(d, d->compat_tc_stats, &d->tc_stats, |
9854518ea sched: align nlat... |
372 |
sizeof(d->tc_stats), d->padattr) < 0) |
1da177e4c Linux-2.6.12-rc2 |
373 374 375 376 |
return -1; if (d->compat_xstats && d->xstats) { if (gnet_stats_copy(d, d->compat_xstats, d->xstats, |
9854518ea sched: align nlat... |
377 |
d->xstats_len, d->padattr) < 0) |
1da177e4c Linux-2.6.12-rc2 |
378 379 |
return -1; } |
edb09eb17 net: sched: do no... |
380 381 |
if (d->lock) spin_unlock_bh(d->lock); |
1c4cff0cf gen_stats.c: Dupl... |
382 383 384 |
kfree(d->xstats); d->xstats = NULL; d->xstats_len = 0; |
1da177e4c Linux-2.6.12-rc2 |
385 386 |
return 0; } |
1da177e4c Linux-2.6.12-rc2 |
387 |
EXPORT_SYMBOL(gnet_stats_finish_copy); |