cbq.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. /*
  2. * lib/route/sch/cbq.c Class Based Queueing
  3. *
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Lesser General Public
  6. * License as published by the Free Software Foundation version 2.1
  7. * of the License.
  8. *
  9. * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
  10. */
  11. #include <netlink-local.h>
  12. #include <netlink-tc.h>
  13. #include <netlink/netlink.h>
  14. #include <netlink/utils.h>
  15. #include <netlink/route/qdisc.h>
  16. #include <netlink/route/qdisc-modules.h>
  17. #include <netlink/route/class.h>
  18. #include <netlink/route/class-modules.h>
  19. #include <netlink/route/link.h>
  20. #include <netlink/route/sch/cbq.h>
  21. #include <netlink/route/cls/police.h>
  22. /**
  23. * @ingroup qdisc_api
  24. * @ingroup class_api
  25. * @defgroup cbq Class Based Queueing (CBQ)
  26. * @{
  27. */
  28. static struct trans_tbl ovl_strategies[] = {
  29. __ADD(TC_CBQ_OVL_CLASSIC,classic)
  30. __ADD(TC_CBQ_OVL_DELAY,delay)
  31. __ADD(TC_CBQ_OVL_LOWPRIO,lowprio)
  32. __ADD(TC_CBQ_OVL_DROP,drop)
  33. __ADD(TC_CBQ_OVL_RCLASSIC,rclassic)
  34. };
  35. /**
  36. * Convert a CBQ OVL strategy to a character string
  37. * @arg type CBQ OVL strategy
  38. * @arg buf destination buffer
  39. * @arg len length of destination buffer
  40. *
  41. * Converts a CBQ OVL strategy to a character string and stores in the
  42. * provided buffer. Returns the destination buffer or the type
  43. * encoded in hex if no match was found.
  44. */
  45. char *nl_ovl_strategy2str(int type, char *buf, size_t len)
  46. {
  47. return __type2str(type, buf, len, ovl_strategies,
  48. ARRAY_SIZE(ovl_strategies));
  49. }
  50. /**
  51. * Convert a string to a CBQ OVL strategy
  52. * @arg name CBQ OVL stragegy name
  53. *
  54. * Converts a CBQ OVL stragegy name to it's corresponding CBQ OVL strategy
  55. * type. Returns the type or -1 if none was found.
  56. */
  57. int nl_str2ovl_strategy(const char *name)
  58. {
  59. return __str2type(name, ovl_strategies, ARRAY_SIZE(ovl_strategies));
  60. }
  61. static struct nla_policy cbq_policy[TCA_CBQ_MAX+1] = {
  62. [TCA_CBQ_LSSOPT] = { .minlen = sizeof(struct tc_cbq_lssopt) },
  63. [TCA_CBQ_RATE] = { .minlen = sizeof(struct tc_ratespec) },
  64. [TCA_CBQ_WRROPT] = { .minlen = sizeof(struct tc_cbq_wrropt) },
  65. [TCA_CBQ_OVL_STRATEGY] = { .minlen = sizeof(struct tc_cbq_ovl) },
  66. [TCA_CBQ_FOPT] = { .minlen = sizeof(struct tc_cbq_fopt) },
  67. [TCA_CBQ_POLICE] = { .minlen = sizeof(struct tc_cbq_police) },
  68. };
  69. static inline struct rtnl_cbq *cbq_qdisc(struct rtnl_tca *tca)
  70. {
  71. return (struct rtnl_cbq *) tca->tc_subdata;
  72. }
  73. static inline struct rtnl_cbq *cbq_alloc(struct rtnl_tca *tca)
  74. {
  75. if (!tca->tc_subdata)
  76. tca->tc_subdata = calloc(1, sizeof(struct rtnl_qdisc));
  77. return cbq_qdisc(tca);
  78. }
  79. static int cbq_msg_parser(struct rtnl_tca *tca)
  80. {
  81. struct nlattr *tb[TCA_CBQ_MAX + 1];
  82. struct rtnl_cbq *cbq;
  83. int err;
  84. err = tca_parse(tb, TCA_CBQ_MAX, tca, cbq_policy);
  85. if (err < 0)
  86. return err;
  87. cbq = cbq_alloc(tca);
  88. if (!cbq)
  89. return nl_errno(ENOMEM);
  90. nla_memcpy(&cbq->cbq_lss, tb[TCA_CBQ_LSSOPT], sizeof(cbq->cbq_lss));
  91. nla_memcpy(&cbq->cbq_rate, tb[TCA_CBQ_RATE], sizeof(cbq->cbq_rate));
  92. nla_memcpy(&cbq->cbq_wrr, tb[TCA_CBQ_WRROPT], sizeof(cbq->cbq_wrr));
  93. nla_memcpy(&cbq->cbq_fopt, tb[TCA_CBQ_FOPT], sizeof(cbq->cbq_fopt));
  94. nla_memcpy(&cbq->cbq_ovl, tb[TCA_CBQ_OVL_STRATEGY],
  95. sizeof(cbq->cbq_ovl));
  96. nla_memcpy(&cbq->cbq_police, tb[TCA_CBQ_POLICE],
  97. sizeof(cbq->cbq_police));
  98. return 0;
  99. }
  100. static int cbq_qdisc_msg_parser(struct rtnl_qdisc *qdisc)
  101. {
  102. return cbq_msg_parser((struct rtnl_tca *) qdisc);
  103. }
  104. static int cbq_class_msg_parser(struct rtnl_class *class)
  105. {
  106. return cbq_msg_parser((struct rtnl_tca *) class);
  107. }
  108. static void cbq_qdisc_free_data(struct rtnl_qdisc *qdisc)
  109. {
  110. free(qdisc->q_subdata);
  111. }
  112. static int cbq_clone(struct rtnl_tca *_dst, struct rtnl_tca *_src)
  113. {
  114. struct rtnl_cbq *src = cbq_qdisc(_src);
  115. if (src && !cbq_alloc(_dst))
  116. return nl_errno(ENOMEM);
  117. else
  118. return 0;
  119. }
  120. static int cbq_qdisc_clone(struct rtnl_qdisc *dst, struct rtnl_qdisc *src)
  121. {
  122. return cbq_clone((struct rtnl_tca *) dst, (struct rtnl_tca *) src);
  123. }
  124. static void cbq_class_free_data(struct rtnl_class *class)
  125. {
  126. free(class->c_subdata);
  127. }
  128. static int cbq_class_clone(struct rtnl_class *dst, struct rtnl_class *src)
  129. {
  130. return cbq_clone((struct rtnl_tca *) dst, (struct rtnl_tca *) src);
  131. }
  132. static int cbq_dump_brief(struct rtnl_tca *tca, struct nl_dump_params *p,
  133. int line)
  134. {
  135. struct rtnl_cbq *cbq;
  136. double r, rbit;
  137. char *ru, *rubit;
  138. cbq = cbq_qdisc(tca);
  139. if (!cbq)
  140. goto ignore;
  141. r = nl_cancel_down_bytes(cbq->cbq_rate.rate, &ru);
  142. rbit = nl_cancel_down_bits(cbq->cbq_rate.rate * 8, &rubit);
  143. dp_dump(p, " rate %.2f%s/s (%.0f%s) prio %u",
  144. r, ru, rbit, rubit, cbq->cbq_wrr.priority);
  145. ignore:
  146. return line;
  147. }
  148. static int cbq_qdisc_dump_brief(struct rtnl_qdisc *qdisc,
  149. struct nl_dump_params *p, int line)
  150. {
  151. return cbq_dump_brief((struct rtnl_tca *) qdisc, p, line);
  152. }
  153. static int cbq_class_dump_brief(struct rtnl_class *class,
  154. struct nl_dump_params *p, int line)
  155. {
  156. return cbq_dump_brief((struct rtnl_tca *) class, p, line);
  157. }
  158. static int cbq_dump_full(struct rtnl_tca *tca, struct nl_dump_params *p,
  159. int line)
  160. {
  161. struct rtnl_cbq *cbq;
  162. char *unit, buf[32];
  163. double w;
  164. uint32_t el;
  165. cbq = cbq_qdisc(tca);
  166. if (!cbq)
  167. goto ignore;
  168. w = nl_cancel_down_bits(cbq->cbq_wrr.weight * 8, &unit);
  169. dp_dump(p, "avgpkt %u mpu %u cell %u allot %u weight %.0f%s\n",
  170. cbq->cbq_lss.avpkt,
  171. cbq->cbq_rate.mpu,
  172. 1 << cbq->cbq_rate.cell_log,
  173. cbq->cbq_wrr.allot, w, unit);
  174. el = cbq->cbq_lss.ewma_log;
  175. dp_dump_line(p, line++, " minidle %uus maxidle %uus offtime "
  176. "%uus level %u ewma_log %u\n",
  177. nl_ticks2us(cbq->cbq_lss.minidle >> el),
  178. nl_ticks2us(cbq->cbq_lss.maxidle >> el),
  179. nl_ticks2us(cbq->cbq_lss.offtime >> el),
  180. cbq->cbq_lss.level,
  181. cbq->cbq_lss.ewma_log);
  182. dp_dump_line(p, line++, " penalty %uus strategy %s ",
  183. nl_ticks2us(cbq->cbq_ovl.penalty),
  184. nl_ovl_strategy2str(cbq->cbq_ovl.strategy, buf, sizeof(buf)));
  185. dp_dump(p, "split %s defmap 0x%08x ",
  186. rtnl_tc_handle2str(cbq->cbq_fopt.split, buf, sizeof(buf)),
  187. cbq->cbq_fopt.defmap);
  188. dp_dump(p, "police %s",
  189. nl_police2str(cbq->cbq_police.police, buf, sizeof(buf)));
  190. ignore:
  191. return line;
  192. }
  193. static int cbq_qdisc_dump_full(struct rtnl_qdisc *qdisc,
  194. struct nl_dump_params *p, int line)
  195. {
  196. return cbq_dump_full((struct rtnl_tca *) qdisc, p, line);
  197. }
  198. static int cbq_class_dump_full(struct rtnl_class *class,
  199. struct nl_dump_params *p, int line)
  200. {
  201. return cbq_dump_full((struct rtnl_tca *) class, p, line);
  202. }
  203. static int cbq_dump_with_stats(struct rtnl_tca *tca, struct nl_dump_params *p,
  204. int line)
  205. {
  206. struct tc_cbq_xstats *x = tca_xstats(tca);
  207. if (!x)
  208. goto ignore;
  209. dp_dump_line(p, line++, " borrows overact "
  210. " avgidle undertime\n");
  211. dp_dump_line(p, line++, " %10u %10u %10u %10u\n",
  212. x->borrows, x->overactions, x->avgidle, x->undertime);
  213. ignore:
  214. return line;
  215. }
  216. static int cbq_qdisc_dump_with_stats(struct rtnl_qdisc *qdisc,
  217. struct nl_dump_params *p, int line)
  218. {
  219. return cbq_dump_with_stats((struct rtnl_tca *) qdisc, p, line);
  220. }
  221. static int cbq_class_dump_with_stats(struct rtnl_class *class,
  222. struct nl_dump_params *p, int line)
  223. {
  224. return cbq_dump_with_stats((struct rtnl_tca *) class, p, line);
  225. }
  226. static struct rtnl_qdisc_ops cbq_qdisc_ops = {
  227. .qo_kind = "cbq",
  228. .qo_msg_parser = cbq_qdisc_msg_parser,
  229. .qo_free_data = cbq_qdisc_free_data,
  230. .qo_clone = cbq_qdisc_clone,
  231. .qo_dump[NL_DUMP_BRIEF] = cbq_qdisc_dump_brief,
  232. .qo_dump[NL_DUMP_FULL] = cbq_qdisc_dump_full,
  233. .qo_dump[NL_DUMP_STATS] = cbq_qdisc_dump_with_stats,
  234. };
  235. static struct rtnl_class_ops cbq_class_ops = {
  236. .co_kind = "cbq",
  237. .co_msg_parser = cbq_class_msg_parser,
  238. .co_free_data = cbq_class_free_data,
  239. .co_clone = cbq_class_clone,
  240. .co_dump[NL_DUMP_BRIEF] = cbq_class_dump_brief,
  241. .co_dump[NL_DUMP_FULL] = cbq_class_dump_full,
  242. .co_dump[NL_DUMP_STATS] = cbq_class_dump_with_stats,
  243. };
  244. static void __init cbq_init(void)
  245. {
  246. rtnl_qdisc_register(&cbq_qdisc_ops);
  247. rtnl_class_register(&cbq_class_ops);
  248. }
  249. static void __exit cbq_exit(void)
  250. {
  251. rtnl_qdisc_unregister(&cbq_qdisc_ops);
  252. rtnl_class_unregister(&cbq_class_ops);
  253. }
  254. /** @} */