Blame view

net/core/gen_stats.c 9.2 KB
1da177e4c   Linus Torvalds   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   Patrick McHardy   [NET_SCHED]: Conv...
23
  #include <net/netlink.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
26
27
28
29
  #include <net/gen_stats.h>
  
  
  static inline int
  gnet_stats_copy(struct gnet_dump *d, int type, void *buf, int size)
  {
14ad6647f   David S. Miller   gen_stats: Stop u...
30
31
  	if (nla_put(d->skb, type, size, buf))
  		goto nla_put_failure;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
  	return 0;
1e90474c3   Patrick McHardy   [NET_SCHED]: Conv...
33
  nla_put_failure:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
  	spin_unlock_bh(d->lock);
  	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
   *
   * 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,
  	int xstats_type, spinlock_t *lock, struct gnet_dump *d)
9a429c498   Eric Dumazet   [NET]: Add some a...
59
  	__acquires(lock)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
60
61
  {
  	memset(d, 0, sizeof(*d));
4ec93edb1   YOSHIFUJI Hideaki   [NET] CORE: Fix w...
62

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63
64
65
  	spin_lock_bh(lock);
  	d->lock = lock;
  	if (type)
1e90474c3   Patrick McHardy   [NET_SCHED]: Conv...
66
  		d->tail = (struct nlattr *)skb_tail_pointer(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67
68
69
70
71
72
73
74
75
  	d->skb = skb;
  	d->compat_tc_stats = tc_stats_type;
  	d->compat_xstats = xstats_type;
  
  	if (d->tail)
  		return gnet_stats_copy(d, type, NULL, 0);
  
  	return 0;
  }
9e34a5b51   Eric Dumazet   net/core: EXPORT_...
76
  EXPORT_SYMBOL(gnet_stats_start_copy_compat);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
  
  /**
   * 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
   * @lock: statistics lock
   * @d: dumping handle
   *
   * 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,
  	struct gnet_dump *d)
  {
  	return gnet_stats_start_copy_compat(skb, type, 0, 0, lock, d);
  }
9e34a5b51   Eric Dumazet   net/core: EXPORT_...
97
  EXPORT_SYMBOL(gnet_stats_start_copy);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
98

22e0f8b93   John Fastabend   net: sched: make ...
99
100
101
102
103
104
105
106
107
  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   WANG Cong   net_sched: fix un...
108
109
  		u64 bytes;
  		u32 packets;
22e0f8b93   John Fastabend   net: sched: make ...
110
111
112
113
114
115
  
  		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   WANG Cong   net_sched: fix un...
116
117
  		bstats->bytes += bytes;
  		bstats->packets += packets;
22e0f8b93   John Fastabend   net: sched: make ...
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
  	}
  }
  
  void
  __gnet_stats_copy_basic(struct gnet_stats_basic_packed *bstats,
  			struct gnet_stats_basic_cpu __percpu *cpu,
  			struct gnet_stats_basic_packed *b)
  {
  	if (cpu) {
  		__gnet_stats_copy_basic_cpu(bstats, cpu);
  	} else {
  		bstats->bytes = b->bytes;
  		bstats->packets = b->packets;
  	}
  }
  EXPORT_SYMBOL(__gnet_stats_copy_basic);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
134
135
136
137
138
139
140
141
142
143
144
145
  /**
   * gnet_stats_copy_basic - copy basic statistics into statistic TLV
   * @d: dumping handle
   * @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
22e0f8b93   John Fastabend   net: sched: make ...
146
147
148
  gnet_stats_copy_basic(struct gnet_dump *d,
  		      struct gnet_stats_basic_cpu __percpu *cpu,
  		      struct gnet_stats_basic_packed *b)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
149
  {
22e0f8b93   John Fastabend   net: sched: make ...
150
151
152
  	struct gnet_stats_basic_packed bstats = {0};
  
  	__gnet_stats_copy_basic(&bstats, cpu, b);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
153
  	if (d->compat_tc_stats) {
22e0f8b93   John Fastabend   net: sched: make ...
154
155
  		d->tc_stats.bytes = bstats.bytes;
  		d->tc_stats.packets = bstats.packets;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
156
  	}
c1a8f1f1c   Eric Dumazet   net: restore gnet...
157
158
  	if (d->tail) {
  		struct gnet_stats_basic sb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
159

c1a8f1f1c   Eric Dumazet   net: restore gnet...
160
  		memset(&sb, 0, sizeof(sb));
22e0f8b93   John Fastabend   net: sched: make ...
161
162
  		sb.bytes = bstats.bytes;
  		sb.packets = bstats.packets;
c1a8f1f1c   Eric Dumazet   net: restore gnet...
163
164
  		return gnet_stats_copy(d, TCA_STATS_BASIC, &sb, sizeof(sb));
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
165
166
  	return 0;
  }
9e34a5b51   Eric Dumazet   net/core: EXPORT_...
167
  EXPORT_SYMBOL(gnet_stats_copy_basic);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
168
169
170
171
  
  /**
   * gnet_stats_copy_rate_est - copy rate estimator statistics into statistics TLV
   * @d: dumping handle
d250a5f90   Eric Dumazet   pkt_sched: gen_es...
172
   * @b: basic statistics
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
173
174
175
176
177
178
179
180
181
   * @r: rate estimator statistics
   *
   * 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   Eric Dumazet   pkt_sched: gen_es...
182
183
  gnet_stats_copy_rate_est(struct gnet_dump *d,
  			 const struct gnet_stats_basic_packed *b,
45203a3b3   Eric Dumazet   net_sched: add 64...
184
  			 struct gnet_stats_rate_est64 *r)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
185
  {
45203a3b3   Eric Dumazet   net_sched: add 64...
186
187
  	struct gnet_stats_rate_est est;
  	int res;
d250a5f90   Eric Dumazet   pkt_sched: gen_es...
188
189
  	if (b && !gen_estimator_active(b, r))
  		return 0;
45203a3b3   Eric Dumazet   net_sched: add 64...
190
191
192
  	est.bps = min_t(u64, UINT_MAX, r->bps);
  	/* we have some time before reaching 2^32 packets per second */
  	est.pps = r->pps;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
193
  	if (d->compat_tc_stats) {
45203a3b3   Eric Dumazet   net_sched: add 64...
194
195
  		d->tc_stats.bps = est.bps;
  		d->tc_stats.pps = est.pps;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
196
  	}
45203a3b3   Eric Dumazet   net_sched: add 64...
197
198
199
200
201
202
203
  	if (d->tail) {
  		res = gnet_stats_copy(d, TCA_STATS_RATE_EST, &est, sizeof(est));
  		if (res < 0 || est.bps == r->bps)
  			return res;
  		/* emit 64bit stats only if needed */
  		return gnet_stats_copy(d, TCA_STATS_RATE_EST64, r, sizeof(*r));
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
204
205
206
  
  	return 0;
  }
9e34a5b51   Eric Dumazet   net/core: EXPORT_...
207
  EXPORT_SYMBOL(gnet_stats_copy_rate_est);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
208

b0ab6f927   John Fastabend   net: sched: enabl...
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
  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   Linus Torvalds   Linux-2.6.12-rc2
243
244
245
  /**
   * gnet_stats_copy_queue - copy queue statistics into statistics TLV
   * @d: dumping handle
b0ab6f927   John Fastabend   net: sched: enabl...
246
   * @cpu_q: per cpu queue statistics
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
247
   * @q: queue statistics
640158536   John Fastabend   net: sched: restr...
248
   * @qlen: queue length statistics
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
249
250
   *
   * Appends the queue statistics to the top level TLV created by
b0ab6f927   John Fastabend   net: sched: enabl...
251
252
   * gnet_stats_start_copy(). Using per cpu queue statistics if
   * they are available.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
253
254
255
256
257
   *
   * Returns 0 on success or -1 with the statistic lock released
   * if the room in the socket buffer was not sufficient.
   */
  int
640158536   John Fastabend   net: sched: restr...
258
  gnet_stats_copy_queue(struct gnet_dump *d,
b0ab6f927   John Fastabend   net: sched: enabl...
259
  		      struct gnet_stats_queue __percpu *cpu_q,
640158536   John Fastabend   net: sched: restr...
260
  		      struct gnet_stats_queue *q, __u32 qlen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
261
  {
b0ab6f927   John Fastabend   net: sched: enabl...
262
263
264
  	struct gnet_stats_queue qstats = {0};
  
  	__gnet_stats_copy_queue(&qstats, cpu_q, q, qlen);
640158536   John Fastabend   net: sched: restr...
265

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
266
  	if (d->compat_tc_stats) {
b0ab6f927   John Fastabend   net: sched: enabl...
267
268
269
270
  		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   Linus Torvalds   Linux-2.6.12-rc2
271
272
273
  	}
  
  	if (d->tail)
b0ab6f927   John Fastabend   net: sched: enabl...
274
275
  		return gnet_stats_copy(d, TCA_STATS_QUEUE,
  				       &qstats, sizeof(qstats));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
276
277
278
  
  	return 0;
  }
9e34a5b51   Eric Dumazet   net/core: EXPORT_...
279
  EXPORT_SYMBOL(gnet_stats_copy_queue);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
280
281
282
283
284
285
286
  
  /**
   * gnet_stats_copy_app - copy application specific statistics into statistics TLV
   * @d: dumping handle
   * @st: application specific statistics data
   * @len: length of data
   *
e793c0f70   Masanari Iida   net: treewide: Fi...
287
   * Appends the application specific statistics to the top level TLV created by
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
   * 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) {
  		d->xstats = st;
  		d->xstats_len = len;
  	}
  
  	if (d->tail)
  		return gnet_stats_copy(d, TCA_STATS_APP, st, len);
  
  	return 0;
  }
9e34a5b51   Eric Dumazet   net/core: EXPORT_...
307
  EXPORT_SYMBOL(gnet_stats_copy_app);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
  
  /**
   * 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   Patrick McHardy   [NET_SCHED]: Conv...
325
  		d->tail->nla_len = skb_tail_pointer(d->skb) - (u8 *)d->tail;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
  
  	if (d->compat_tc_stats)
  		if (gnet_stats_copy(d, d->compat_tc_stats, &d->tc_stats,
  			sizeof(d->tc_stats)) < 0)
  			return -1;
  
  	if (d->compat_xstats && d->xstats) {
  		if (gnet_stats_copy(d, d->compat_xstats, d->xstats,
  			d->xstats_len) < 0)
  			return -1;
  	}
  
  	spin_unlock_bh(d->lock);
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
341
  EXPORT_SYMBOL(gnet_stats_finish_copy);