gen_stats.c 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. /*
  2. * net/core/gen_stats.c
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License
  6. * as published by the Free Software Foundation; either version
  7. * 2 of the License, or (at your option) any later version.
  8. *
  9. * Authors: Thomas Graf <tgraf@suug.ch>
  10. * Jamal Hadi Salim
  11. * Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
  12. *
  13. * See Documentation/networking/gen_stats.txt
  14. */
  15. #include <linux/types.h>
  16. #include <linux/kernel.h>
  17. #include <linux/module.h>
  18. #include <linux/interrupt.h>
  19. #include <linux/socket.h>
  20. #include <linux/rtnetlink.h>
  21. #include <linux/gen_stats.h>
  22. #include <net/netlink.h>
  23. #include <net/gen_stats.h>
  24. static inline int
  25. gnet_stats_copy(struct gnet_dump *d, int type, void *buf, int size)
  26. {
  27. if (nla_put(d->skb, type, size, buf))
  28. goto nla_put_failure;
  29. return 0;
  30. nla_put_failure:
  31. spin_unlock_bh(d->lock);
  32. return -1;
  33. }
  34. /**
  35. * gnet_stats_start_copy_compat - start dumping procedure in compatibility mode
  36. * @skb: socket buffer to put statistics TLVs into
  37. * @type: TLV type for top level statistic TLV
  38. * @tc_stats_type: TLV type for backward compatibility struct tc_stats TLV
  39. * @xstats_type: TLV type for backward compatibility xstats TLV
  40. * @lock: statistics lock
  41. * @d: dumping handle
  42. *
  43. * Initializes the dumping handle, grabs the statistic lock and appends
  44. * an empty TLV header to the socket buffer for use a container for all
  45. * other statistic TLVS.
  46. *
  47. * The dumping handle is marked to be in backward compatibility mode telling
  48. * all gnet_stats_copy_XXX() functions to fill a local copy of struct tc_stats.
  49. *
  50. * Returns 0 on success or -1 if the room in the socket buffer was not sufficient.
  51. */
  52. int
  53. gnet_stats_start_copy_compat(struct sk_buff *skb, int type, int tc_stats_type,
  54. int xstats_type, spinlock_t *lock, struct gnet_dump *d)
  55. __acquires(lock)
  56. {
  57. memset(d, 0, sizeof(*d));
  58. spin_lock_bh(lock);
  59. d->lock = lock;
  60. if (type)
  61. d->tail = (struct nlattr *)skb_tail_pointer(skb);
  62. d->skb = skb;
  63. d->compat_tc_stats = tc_stats_type;
  64. d->compat_xstats = xstats_type;
  65. if (d->tail)
  66. return gnet_stats_copy(d, type, NULL, 0);
  67. return 0;
  68. }
  69. EXPORT_SYMBOL(gnet_stats_start_copy_compat);
  70. /**
  71. * gnet_stats_start_copy_compat - start dumping procedure in compatibility mode
  72. * @skb: socket buffer to put statistics TLVs into
  73. * @type: TLV type for top level statistic TLV
  74. * @lock: statistics lock
  75. * @d: dumping handle
  76. *
  77. * Initializes the dumping handle, grabs the statistic lock and appends
  78. * an empty TLV header to the socket buffer for use a container for all
  79. * other statistic TLVS.
  80. *
  81. * Returns 0 on success or -1 if the room in the socket buffer was not sufficient.
  82. */
  83. int
  84. gnet_stats_start_copy(struct sk_buff *skb, int type, spinlock_t *lock,
  85. struct gnet_dump *d)
  86. {
  87. return gnet_stats_start_copy_compat(skb, type, 0, 0, lock, d);
  88. }
  89. EXPORT_SYMBOL(gnet_stats_start_copy);
  90. static void
  91. __gnet_stats_copy_basic_cpu(struct gnet_stats_basic_packed *bstats,
  92. struct gnet_stats_basic_cpu __percpu *cpu)
  93. {
  94. int i;
  95. for_each_possible_cpu(i) {
  96. struct gnet_stats_basic_cpu *bcpu = per_cpu_ptr(cpu, i);
  97. unsigned int start;
  98. u64 bytes;
  99. u32 packets;
  100. do {
  101. start = u64_stats_fetch_begin_irq(&bcpu->syncp);
  102. bytes = bcpu->bstats.bytes;
  103. packets = bcpu->bstats.packets;
  104. } while (u64_stats_fetch_retry_irq(&bcpu->syncp, start));
  105. bstats->bytes += bytes;
  106. bstats->packets += packets;
  107. }
  108. }
  109. void
  110. __gnet_stats_copy_basic(struct gnet_stats_basic_packed *bstats,
  111. struct gnet_stats_basic_cpu __percpu *cpu,
  112. struct gnet_stats_basic_packed *b)
  113. {
  114. if (cpu) {
  115. __gnet_stats_copy_basic_cpu(bstats, cpu);
  116. } else {
  117. bstats->bytes = b->bytes;
  118. bstats->packets = b->packets;
  119. }
  120. }
  121. EXPORT_SYMBOL(__gnet_stats_copy_basic);
  122. /**
  123. * gnet_stats_copy_basic - copy basic statistics into statistic TLV
  124. * @d: dumping handle
  125. * @b: basic statistics
  126. *
  127. * Appends the basic statistics to the top level TLV created by
  128. * gnet_stats_start_copy().
  129. *
  130. * Returns 0 on success or -1 with the statistic lock released
  131. * if the room in the socket buffer was not sufficient.
  132. */
  133. int
  134. gnet_stats_copy_basic(struct gnet_dump *d,
  135. struct gnet_stats_basic_cpu __percpu *cpu,
  136. struct gnet_stats_basic_packed *b)
  137. {
  138. struct gnet_stats_basic_packed bstats = {0};
  139. __gnet_stats_copy_basic(&bstats, cpu, b);
  140. if (d->compat_tc_stats) {
  141. d->tc_stats.bytes = bstats.bytes;
  142. d->tc_stats.packets = bstats.packets;
  143. }
  144. if (d->tail) {
  145. struct gnet_stats_basic sb;
  146. memset(&sb, 0, sizeof(sb));
  147. sb.bytes = bstats.bytes;
  148. sb.packets = bstats.packets;
  149. return gnet_stats_copy(d, TCA_STATS_BASIC, &sb, sizeof(sb));
  150. }
  151. return 0;
  152. }
  153. EXPORT_SYMBOL(gnet_stats_copy_basic);
  154. /**
  155. * gnet_stats_copy_rate_est - copy rate estimator statistics into statistics TLV
  156. * @d: dumping handle
  157. * @b: basic statistics
  158. * @r: rate estimator statistics
  159. *
  160. * Appends the rate estimator statistics to the top level TLV created by
  161. * gnet_stats_start_copy().
  162. *
  163. * Returns 0 on success or -1 with the statistic lock released
  164. * if the room in the socket buffer was not sufficient.
  165. */
  166. int
  167. gnet_stats_copy_rate_est(struct gnet_dump *d,
  168. const struct gnet_stats_basic_packed *b,
  169. struct gnet_stats_rate_est64 *r)
  170. {
  171. struct gnet_stats_rate_est est;
  172. int res;
  173. if (b && !gen_estimator_active(b, r))
  174. return 0;
  175. est.bps = min_t(u64, UINT_MAX, r->bps);
  176. /* we have some time before reaching 2^32 packets per second */
  177. est.pps = r->pps;
  178. if (d->compat_tc_stats) {
  179. d->tc_stats.bps = est.bps;
  180. d->tc_stats.pps = est.pps;
  181. }
  182. if (d->tail) {
  183. res = gnet_stats_copy(d, TCA_STATS_RATE_EST, &est, sizeof(est));
  184. if (res < 0 || est.bps == r->bps)
  185. return res;
  186. /* emit 64bit stats only if needed */
  187. return gnet_stats_copy(d, TCA_STATS_RATE_EST64, r, sizeof(*r));
  188. }
  189. return 0;
  190. }
  191. EXPORT_SYMBOL(gnet_stats_copy_rate_est);
  192. static void
  193. __gnet_stats_copy_queue_cpu(struct gnet_stats_queue *qstats,
  194. const struct gnet_stats_queue __percpu *q)
  195. {
  196. int i;
  197. for_each_possible_cpu(i) {
  198. const struct gnet_stats_queue *qcpu = per_cpu_ptr(q, i);
  199. qstats->qlen = 0;
  200. qstats->backlog += qcpu->backlog;
  201. qstats->drops += qcpu->drops;
  202. qstats->requeues += qcpu->requeues;
  203. qstats->overlimits += qcpu->overlimits;
  204. }
  205. }
  206. static void __gnet_stats_copy_queue(struct gnet_stats_queue *qstats,
  207. const struct gnet_stats_queue __percpu *cpu,
  208. const struct gnet_stats_queue *q,
  209. __u32 qlen)
  210. {
  211. if (cpu) {
  212. __gnet_stats_copy_queue_cpu(qstats, cpu);
  213. } else {
  214. qstats->qlen = q->qlen;
  215. qstats->backlog = q->backlog;
  216. qstats->drops = q->drops;
  217. qstats->requeues = q->requeues;
  218. qstats->overlimits = q->overlimits;
  219. }
  220. qstats->qlen = qlen;
  221. }
  222. /**
  223. * gnet_stats_copy_queue - copy queue statistics into statistics TLV
  224. * @d: dumping handle
  225. * @cpu_q: per cpu queue statistics
  226. * @q: queue statistics
  227. * @qlen: queue length statistics
  228. *
  229. * Appends the queue statistics to the top level TLV created by
  230. * gnet_stats_start_copy(). Using per cpu queue statistics if
  231. * they are available.
  232. *
  233. * Returns 0 on success or -1 with the statistic lock released
  234. * if the room in the socket buffer was not sufficient.
  235. */
  236. int
  237. gnet_stats_copy_queue(struct gnet_dump *d,
  238. struct gnet_stats_queue __percpu *cpu_q,
  239. struct gnet_stats_queue *q, __u32 qlen)
  240. {
  241. struct gnet_stats_queue qstats = {0};
  242. __gnet_stats_copy_queue(&qstats, cpu_q, q, qlen);
  243. if (d->compat_tc_stats) {
  244. d->tc_stats.drops = qstats.drops;
  245. d->tc_stats.qlen = qstats.qlen;
  246. d->tc_stats.backlog = qstats.backlog;
  247. d->tc_stats.overlimits = qstats.overlimits;
  248. }
  249. if (d->tail)
  250. return gnet_stats_copy(d, TCA_STATS_QUEUE,
  251. &qstats, sizeof(qstats));
  252. return 0;
  253. }
  254. EXPORT_SYMBOL(gnet_stats_copy_queue);
  255. /**
  256. * gnet_stats_copy_app - copy application specific statistics into statistics TLV
  257. * @d: dumping handle
  258. * @st: application specific statistics data
  259. * @len: length of data
  260. *
  261. * Appends the application specific statistics to the top level TLV created by
  262. * gnet_stats_start_copy() and remembers the data for XSTATS if the dumping
  263. * handle is in backward compatibility mode.
  264. *
  265. * Returns 0 on success or -1 with the statistic lock released
  266. * if the room in the socket buffer was not sufficient.
  267. */
  268. int
  269. gnet_stats_copy_app(struct gnet_dump *d, void *st, int len)
  270. {
  271. if (d->compat_xstats) {
  272. d->xstats = st;
  273. d->xstats_len = len;
  274. }
  275. if (d->tail)
  276. return gnet_stats_copy(d, TCA_STATS_APP, st, len);
  277. return 0;
  278. }
  279. EXPORT_SYMBOL(gnet_stats_copy_app);
  280. /**
  281. * gnet_stats_finish_copy - finish dumping procedure
  282. * @d: dumping handle
  283. *
  284. * Corrects the length of the top level TLV to include all TLVs added
  285. * by gnet_stats_copy_XXX() calls. Adds the backward compatibility TLVs
  286. * if gnet_stats_start_copy_compat() was used and releases the statistics
  287. * lock.
  288. *
  289. * Returns 0 on success or -1 with the statistic lock released
  290. * if the room in the socket buffer was not sufficient.
  291. */
  292. int
  293. gnet_stats_finish_copy(struct gnet_dump *d)
  294. {
  295. if (d->tail)
  296. d->tail->nla_len = skb_tail_pointer(d->skb) - (u8 *)d->tail;
  297. if (d->compat_tc_stats)
  298. if (gnet_stats_copy(d, d->compat_tc_stats, &d->tc_stats,
  299. sizeof(d->tc_stats)) < 0)
  300. return -1;
  301. if (d->compat_xstats && d->xstats) {
  302. if (gnet_stats_copy(d, d->compat_xstats, d->xstats,
  303. d->xstats_len) < 0)
  304. return -1;
  305. }
  306. spin_unlock_bh(d->lock);
  307. return 0;
  308. }
  309. EXPORT_SYMBOL(gnet_stats_finish_copy);