gen_stats.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  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, int padattr)
  26. {
  27. if (nla_put_64bit(d->skb, type, size, buf, padattr))
  28. goto nla_put_failure;
  29. return 0;
  30. nla_put_failure:
  31. if (d->lock)
  32. spin_unlock_bh(d->lock);
  33. kfree(d->xstats);
  34. d->xstats = NULL;
  35. d->xstats_len = 0;
  36. return -1;
  37. }
  38. /**
  39. * gnet_stats_start_copy_compat - start dumping procedure in compatibility mode
  40. * @skb: socket buffer to put statistics TLVs into
  41. * @type: TLV type for top level statistic TLV
  42. * @tc_stats_type: TLV type for backward compatibility struct tc_stats TLV
  43. * @xstats_type: TLV type for backward compatibility xstats TLV
  44. * @lock: statistics lock
  45. * @d: dumping handle
  46. * @padattr: padding attribute
  47. *
  48. * Initializes the dumping handle, grabs the statistic lock and appends
  49. * an empty TLV header to the socket buffer for use a container for all
  50. * other statistic TLVS.
  51. *
  52. * The dumping handle is marked to be in backward compatibility mode telling
  53. * all gnet_stats_copy_XXX() functions to fill a local copy of struct tc_stats.
  54. *
  55. * Returns 0 on success or -1 if the room in the socket buffer was not sufficient.
  56. */
  57. int
  58. gnet_stats_start_copy_compat(struct sk_buff *skb, int type, int tc_stats_type,
  59. int xstats_type, spinlock_t *lock,
  60. struct gnet_dump *d, int padattr)
  61. __acquires(lock)
  62. {
  63. memset(d, 0, sizeof(*d));
  64. if (type)
  65. d->tail = (struct nlattr *)skb_tail_pointer(skb);
  66. d->skb = skb;
  67. d->compat_tc_stats = tc_stats_type;
  68. d->compat_xstats = xstats_type;
  69. d->padattr = padattr;
  70. if (lock) {
  71. d->lock = lock;
  72. spin_lock_bh(lock);
  73. }
  74. if (d->tail) {
  75. int ret = gnet_stats_copy(d, type, NULL, 0, padattr);
  76. /* The initial attribute added in gnet_stats_copy() may be
  77. * preceded by a padding attribute, in which case d->tail will
  78. * end up pointing at the padding instead of the real attribute.
  79. * Fix this so gnet_stats_finish_copy() adjusts the length of
  80. * the right attribute.
  81. */
  82. if (ret == 0 && d->tail->nla_type == padattr)
  83. d->tail = (struct nlattr *)((char *)d->tail +
  84. NLA_ALIGN(d->tail->nla_len));
  85. return ret;
  86. }
  87. return 0;
  88. }
  89. EXPORT_SYMBOL(gnet_stats_start_copy_compat);
  90. /**
  91. * gnet_stats_start_copy - start dumping procedure in compatibility mode
  92. * @skb: socket buffer to put statistics TLVs into
  93. * @type: TLV type for top level statistic TLV
  94. * @lock: statistics lock
  95. * @d: dumping handle
  96. * @padattr: padding attribute
  97. *
  98. * Initializes the dumping handle, grabs the statistic lock and appends
  99. * an empty TLV header to the socket buffer for use a container for all
  100. * other statistic TLVS.
  101. *
  102. * Returns 0 on success or -1 if the room in the socket buffer was not sufficient.
  103. */
  104. int
  105. gnet_stats_start_copy(struct sk_buff *skb, int type, spinlock_t *lock,
  106. struct gnet_dump *d, int padattr)
  107. {
  108. return gnet_stats_start_copy_compat(skb, type, 0, 0, lock, d, padattr);
  109. }
  110. EXPORT_SYMBOL(gnet_stats_start_copy);
  111. static void
  112. __gnet_stats_copy_basic_cpu(struct gnet_stats_basic_packed *bstats,
  113. struct gnet_stats_basic_cpu __percpu *cpu)
  114. {
  115. int i;
  116. for_each_possible_cpu(i) {
  117. struct gnet_stats_basic_cpu *bcpu = per_cpu_ptr(cpu, i);
  118. unsigned int start;
  119. u64 bytes;
  120. u32 packets;
  121. do {
  122. start = u64_stats_fetch_begin_irq(&bcpu->syncp);
  123. bytes = bcpu->bstats.bytes;
  124. packets = bcpu->bstats.packets;
  125. } while (u64_stats_fetch_retry_irq(&bcpu->syncp, start));
  126. bstats->bytes += bytes;
  127. bstats->packets += packets;
  128. }
  129. }
  130. void
  131. __gnet_stats_copy_basic(const seqcount_t *running,
  132. struct gnet_stats_basic_packed *bstats,
  133. struct gnet_stats_basic_cpu __percpu *cpu,
  134. struct gnet_stats_basic_packed *b)
  135. {
  136. unsigned int seq;
  137. if (cpu) {
  138. __gnet_stats_copy_basic_cpu(bstats, cpu);
  139. return;
  140. }
  141. do {
  142. if (running)
  143. seq = read_seqcount_begin(running);
  144. bstats->bytes = b->bytes;
  145. bstats->packets = b->packets;
  146. } while (running && read_seqcount_retry(running, seq));
  147. }
  148. EXPORT_SYMBOL(__gnet_stats_copy_basic);
  149. static int
  150. ___gnet_stats_copy_basic(const seqcount_t *running,
  151. struct gnet_dump *d,
  152. struct gnet_stats_basic_cpu __percpu *cpu,
  153. struct gnet_stats_basic_packed *b,
  154. int type)
  155. {
  156. struct gnet_stats_basic_packed bstats = {0};
  157. __gnet_stats_copy_basic(running, &bstats, cpu, b);
  158. if (d->compat_tc_stats && type == TCA_STATS_BASIC) {
  159. d->tc_stats.bytes = bstats.bytes;
  160. d->tc_stats.packets = bstats.packets;
  161. }
  162. if (d->tail) {
  163. struct gnet_stats_basic sb;
  164. memset(&sb, 0, sizeof(sb));
  165. sb.bytes = bstats.bytes;
  166. sb.packets = bstats.packets;
  167. return gnet_stats_copy(d, type, &sb, sizeof(sb),
  168. TCA_STATS_PAD);
  169. }
  170. return 0;
  171. }
  172. /**
  173. * gnet_stats_copy_basic - copy basic statistics into statistic TLV
  174. * @running: seqcount_t pointer
  175. * @d: dumping handle
  176. * @cpu: copy statistic per cpu
  177. * @b: basic statistics
  178. *
  179. * Appends the basic statistics to the top level TLV created by
  180. * gnet_stats_start_copy().
  181. *
  182. * Returns 0 on success or -1 with the statistic lock released
  183. * if the room in the socket buffer was not sufficient.
  184. */
  185. int
  186. gnet_stats_copy_basic(const seqcount_t *running,
  187. struct gnet_dump *d,
  188. struct gnet_stats_basic_cpu __percpu *cpu,
  189. struct gnet_stats_basic_packed *b)
  190. {
  191. return ___gnet_stats_copy_basic(running, d, cpu, b,
  192. TCA_STATS_BASIC);
  193. }
  194. EXPORT_SYMBOL(gnet_stats_copy_basic);
  195. /**
  196. * gnet_stats_copy_basic_hw - copy basic hw statistics into statistic TLV
  197. * @running: seqcount_t pointer
  198. * @d: dumping handle
  199. * @cpu: copy statistic per cpu
  200. * @b: basic statistics
  201. *
  202. * Appends the basic statistics to the top level TLV created by
  203. * gnet_stats_start_copy().
  204. *
  205. * Returns 0 on success or -1 with the statistic lock released
  206. * if the room in the socket buffer was not sufficient.
  207. */
  208. int
  209. gnet_stats_copy_basic_hw(const seqcount_t *running,
  210. struct gnet_dump *d,
  211. struct gnet_stats_basic_cpu __percpu *cpu,
  212. struct gnet_stats_basic_packed *b)
  213. {
  214. return ___gnet_stats_copy_basic(running, d, cpu, b,
  215. TCA_STATS_BASIC_HW);
  216. }
  217. EXPORT_SYMBOL(gnet_stats_copy_basic_hw);
  218. /**
  219. * gnet_stats_copy_rate_est - copy rate estimator statistics into statistics TLV
  220. * @d: dumping handle
  221. * @rate_est: rate estimator
  222. *
  223. * Appends the rate estimator statistics to the top level TLV created by
  224. * gnet_stats_start_copy().
  225. *
  226. * Returns 0 on success or -1 with the statistic lock released
  227. * if the room in the socket buffer was not sufficient.
  228. */
  229. int
  230. gnet_stats_copy_rate_est(struct gnet_dump *d,
  231. struct net_rate_estimator __rcu **rate_est)
  232. {
  233. struct gnet_stats_rate_est64 sample;
  234. struct gnet_stats_rate_est est;
  235. int res;
  236. if (!gen_estimator_read(rate_est, &sample))
  237. return 0;
  238. est.bps = min_t(u64, UINT_MAX, sample.bps);
  239. /* we have some time before reaching 2^32 packets per second */
  240. est.pps = sample.pps;
  241. if (d->compat_tc_stats) {
  242. d->tc_stats.bps = est.bps;
  243. d->tc_stats.pps = est.pps;
  244. }
  245. if (d->tail) {
  246. res = gnet_stats_copy(d, TCA_STATS_RATE_EST, &est, sizeof(est),
  247. TCA_STATS_PAD);
  248. if (res < 0 || est.bps == sample.bps)
  249. return res;
  250. /* emit 64bit stats only if needed */
  251. return gnet_stats_copy(d, TCA_STATS_RATE_EST64, &sample,
  252. sizeof(sample), TCA_STATS_PAD);
  253. }
  254. return 0;
  255. }
  256. EXPORT_SYMBOL(gnet_stats_copy_rate_est);
  257. static void
  258. __gnet_stats_copy_queue_cpu(struct gnet_stats_queue *qstats,
  259. const struct gnet_stats_queue __percpu *q)
  260. {
  261. int i;
  262. for_each_possible_cpu(i) {
  263. const struct gnet_stats_queue *qcpu = per_cpu_ptr(q, i);
  264. qstats->qlen = 0;
  265. qstats->backlog += qcpu->backlog;
  266. qstats->drops += qcpu->drops;
  267. qstats->requeues += qcpu->requeues;
  268. qstats->overlimits += qcpu->overlimits;
  269. }
  270. }
  271. void __gnet_stats_copy_queue(struct gnet_stats_queue *qstats,
  272. const struct gnet_stats_queue __percpu *cpu,
  273. const struct gnet_stats_queue *q,
  274. __u32 qlen)
  275. {
  276. if (cpu) {
  277. __gnet_stats_copy_queue_cpu(qstats, cpu);
  278. } else {
  279. qstats->qlen = q->qlen;
  280. qstats->backlog = q->backlog;
  281. qstats->drops = q->drops;
  282. qstats->requeues = q->requeues;
  283. qstats->overlimits = q->overlimits;
  284. }
  285. qstats->qlen = qlen;
  286. }
  287. EXPORT_SYMBOL(__gnet_stats_copy_queue);
  288. /**
  289. * gnet_stats_copy_queue - copy queue statistics into statistics TLV
  290. * @d: dumping handle
  291. * @cpu_q: per cpu queue statistics
  292. * @q: queue statistics
  293. * @qlen: queue length statistics
  294. *
  295. * Appends the queue statistics to the top level TLV created by
  296. * gnet_stats_start_copy(). Using per cpu queue statistics if
  297. * they are available.
  298. *
  299. * Returns 0 on success or -1 with the statistic lock released
  300. * if the room in the socket buffer was not sufficient.
  301. */
  302. int
  303. gnet_stats_copy_queue(struct gnet_dump *d,
  304. struct gnet_stats_queue __percpu *cpu_q,
  305. struct gnet_stats_queue *q, __u32 qlen)
  306. {
  307. struct gnet_stats_queue qstats = {0};
  308. __gnet_stats_copy_queue(&qstats, cpu_q, q, qlen);
  309. if (d->compat_tc_stats) {
  310. d->tc_stats.drops = qstats.drops;
  311. d->tc_stats.qlen = qstats.qlen;
  312. d->tc_stats.backlog = qstats.backlog;
  313. d->tc_stats.overlimits = qstats.overlimits;
  314. }
  315. if (d->tail)
  316. return gnet_stats_copy(d, TCA_STATS_QUEUE,
  317. &qstats, sizeof(qstats),
  318. TCA_STATS_PAD);
  319. return 0;
  320. }
  321. EXPORT_SYMBOL(gnet_stats_copy_queue);
  322. /**
  323. * gnet_stats_copy_app - copy application specific statistics into statistics TLV
  324. * @d: dumping handle
  325. * @st: application specific statistics data
  326. * @len: length of data
  327. *
  328. * Appends the application specific statistics to the top level TLV created by
  329. * gnet_stats_start_copy() and remembers the data for XSTATS if the dumping
  330. * handle is in backward compatibility mode.
  331. *
  332. * Returns 0 on success or -1 with the statistic lock released
  333. * if the room in the socket buffer was not sufficient.
  334. */
  335. int
  336. gnet_stats_copy_app(struct gnet_dump *d, void *st, int len)
  337. {
  338. if (d->compat_xstats) {
  339. d->xstats = kmemdup(st, len, GFP_ATOMIC);
  340. if (!d->xstats)
  341. goto err_out;
  342. d->xstats_len = len;
  343. }
  344. if (d->tail)
  345. return gnet_stats_copy(d, TCA_STATS_APP, st, len,
  346. TCA_STATS_PAD);
  347. return 0;
  348. err_out:
  349. if (d->lock)
  350. spin_unlock_bh(d->lock);
  351. d->xstats_len = 0;
  352. return -1;
  353. }
  354. EXPORT_SYMBOL(gnet_stats_copy_app);
  355. /**
  356. * gnet_stats_finish_copy - finish dumping procedure
  357. * @d: dumping handle
  358. *
  359. * Corrects the length of the top level TLV to include all TLVs added
  360. * by gnet_stats_copy_XXX() calls. Adds the backward compatibility TLVs
  361. * if gnet_stats_start_copy_compat() was used and releases the statistics
  362. * lock.
  363. *
  364. * Returns 0 on success or -1 with the statistic lock released
  365. * if the room in the socket buffer was not sufficient.
  366. */
  367. int
  368. gnet_stats_finish_copy(struct gnet_dump *d)
  369. {
  370. if (d->tail)
  371. d->tail->nla_len = skb_tail_pointer(d->skb) - (u8 *)d->tail;
  372. if (d->compat_tc_stats)
  373. if (gnet_stats_copy(d, d->compat_tc_stats, &d->tc_stats,
  374. sizeof(d->tc_stats), d->padattr) < 0)
  375. return -1;
  376. if (d->compat_xstats && d->xstats) {
  377. if (gnet_stats_copy(d, d->compat_xstats, d->xstats,
  378. d->xstats_len, d->padattr) < 0)
  379. return -1;
  380. }
  381. if (d->lock)
  382. spin_unlock_bh(d->lock);
  383. kfree(d->xstats);
  384. d->xstats = NULL;
  385. d->xstats_len = 0;
  386. return 0;
  387. }
  388. EXPORT_SYMBOL(gnet_stats_finish_copy);