prio.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. /*
  2. * lib/route/sch/prio.c PRIO Qdisc/Class
  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. /**
  12. * @ingroup qdisc_api
  13. * @defgroup prio (Fast) Prio
  14. * @brief
  15. *
  16. * @par 1) Typical PRIO configuration
  17. * @code
  18. * // Specify the maximal number of bands to be used for this PRIO qdisc.
  19. * rtnl_qdisc_prio_set_bands(qdisc, QDISC_PRIO_DEFAULT_BANDS);
  20. *
  21. * // Provide a map assigning each priority to a band number.
  22. * uint8_t map[] = QDISC_PRIO_DEFAULT_PRIOMAP;
  23. * rtnl_qdisc_prio_set_priomap(qdisc, map, sizeof(map));
  24. * @endcode
  25. * @{
  26. */
  27. #include <netlink-local.h>
  28. #include <netlink-tc.h>
  29. #include <netlink/netlink.h>
  30. #include <netlink/utils.h>
  31. #include <netlink/route/qdisc.h>
  32. #include <netlink/route/qdisc-modules.h>
  33. #include <netlink/route/sch/prio.h>
  34. /** @cond SKIP */
  35. #define SCH_PRIO_ATTR_BANDS 1
  36. #define SCH_PRIO_ATTR_PRIOMAP 2
  37. /** @endcond */
  38. static inline struct rtnl_prio *prio_qdisc(struct rtnl_qdisc *qdisc)
  39. {
  40. return (struct rtnl_prio *) qdisc->q_subdata;
  41. }
  42. static inline struct rtnl_prio *prio_alloc(struct rtnl_qdisc *qdisc)
  43. {
  44. if (!qdisc->q_subdata)
  45. qdisc->q_subdata = calloc(1, sizeof(struct rtnl_prio));
  46. return prio_qdisc(qdisc);
  47. }
  48. static int prio_msg_parser(struct rtnl_qdisc *qdisc)
  49. {
  50. struct rtnl_prio *prio;
  51. struct tc_prio_qopt *opt;
  52. if (qdisc->q_opts->d_size < sizeof(*opt))
  53. return nl_error(EINVAL, "prio specific option size mismatch");
  54. prio = prio_alloc(qdisc);
  55. if (!prio)
  56. return nl_errno(ENOMEM);
  57. opt = (struct tc_prio_qopt *) qdisc->q_opts->d_data;
  58. prio->qp_bands = opt->bands;
  59. memcpy(prio->qp_priomap, opt->priomap, sizeof(prio->qp_priomap));
  60. prio->qp_mask = (SCH_PRIO_ATTR_BANDS | SCH_PRIO_ATTR_PRIOMAP);
  61. return 0;
  62. }
  63. static void prio_free_data(struct rtnl_qdisc *qdisc)
  64. {
  65. free(qdisc->q_subdata);
  66. }
  67. static int prio_dump_brief(struct rtnl_qdisc *qdisc,
  68. struct nl_dump_params *p, int line)
  69. {
  70. struct rtnl_prio *prio = prio_qdisc(qdisc);
  71. if (prio)
  72. dp_dump(p, " bands %u", prio->qp_bands);
  73. return line;
  74. }
  75. static int prio_dump_full(struct rtnl_qdisc *qdisc,
  76. struct nl_dump_params *p, int line)
  77. {
  78. struct rtnl_prio *prio = prio_qdisc(qdisc);
  79. int i, hp;
  80. if (!prio)
  81. goto ignore;
  82. dp_dump(p, "priomap [");
  83. for (i = 0; i <= TC_PRIO_MAX; i++)
  84. dp_dump(p, "%u%s", prio->qp_priomap[i],
  85. i < TC_PRIO_MAX ? " " : "");
  86. dp_dump(p, "]\n");
  87. dp_new_line(p, line++);
  88. hp = (((TC_PRIO_MAX/2) + 1) & ~1);
  89. for (i = 0; i < hp; i++) {
  90. char a[32];
  91. dp_dump(p, " %18s => %u",
  92. rtnl_prio2str(i, a, sizeof(a)),
  93. prio->qp_priomap[i]);
  94. if (hp+i <= TC_PRIO_MAX) {
  95. dp_dump(p, " %18s => %u",
  96. rtnl_prio2str(hp+i, a, sizeof(a)),
  97. prio->qp_priomap[hp+i]);
  98. if (i < (hp - 1)) {
  99. dp_dump(p, "\n");
  100. dp_new_line(p, line++);
  101. }
  102. }
  103. }
  104. ignore:
  105. return line;
  106. }
  107. static struct nl_msg *prio_get_opts(struct rtnl_qdisc *qdisc)
  108. {
  109. struct rtnl_prio *prio;
  110. struct tc_prio_qopt opts;
  111. struct nl_msg *msg;
  112. prio = prio_qdisc(qdisc);
  113. if (!prio ||
  114. !(prio->qp_mask & SCH_PRIO_ATTR_PRIOMAP))
  115. goto errout;
  116. opts.bands = prio->qp_bands;
  117. memcpy(opts.priomap, prio->qp_priomap, sizeof(opts.priomap));
  118. msg = nlmsg_alloc();
  119. if (!msg)
  120. goto errout;
  121. if (nlmsg_append(msg, &opts, sizeof(opts), NL_DONTPAD) < 0) {
  122. nlmsg_free(msg);
  123. goto errout;
  124. }
  125. return msg;
  126. errout:
  127. return NULL;
  128. }
  129. /**
  130. * @name Attribute Modification
  131. * @{
  132. */
  133. /**
  134. * Set number of bands of PRIO qdisc.
  135. * @arg qdisc PRIO qdisc to be modified.
  136. * @arg bands New number of bands.
  137. * @return 0 on success or a negative error code.
  138. */
  139. int rtnl_qdisc_prio_set_bands(struct rtnl_qdisc *qdisc, int bands)
  140. {
  141. struct rtnl_prio *prio;
  142. prio = prio_alloc(qdisc);
  143. if (!prio)
  144. return nl_errno(ENOMEM);
  145. prio->qp_bands = bands;
  146. prio->qp_mask |= SCH_PRIO_ATTR_BANDS;
  147. return 0;
  148. }
  149. /**
  150. * Get number of bands of PRIO qdisc.
  151. * @arg qdisc PRIO qdisc.
  152. * @return Number of bands or a negative error code.
  153. */
  154. int rtnl_qdisc_prio_get_bands(struct rtnl_qdisc *qdisc)
  155. {
  156. struct rtnl_prio *prio;
  157. prio = prio_qdisc(qdisc);
  158. if (prio && prio->qp_mask & SCH_PRIO_ATTR_BANDS)
  159. return prio->qp_bands;
  160. else
  161. return nl_errno(ENOMEM);
  162. }
  163. /**
  164. * Set priomap of the PRIO qdisc.
  165. * @arg qdisc PRIO qdisc to be modified.
  166. * @arg priomap New priority mapping.
  167. * @arg len Length of priomap (# of elements).
  168. * @return 0 on success or a negative error code.
  169. */
  170. int rtnl_qdisc_prio_set_priomap(struct rtnl_qdisc *qdisc, uint8_t priomap[],
  171. int len)
  172. {
  173. struct rtnl_prio *prio;
  174. int i;
  175. prio = prio_alloc(qdisc);
  176. if (!prio)
  177. return nl_errno(ENOMEM);
  178. if (!(prio->qp_mask & SCH_PRIO_ATTR_BANDS))
  179. return nl_error(EINVAL, "Set number of bands first");
  180. if ((len / sizeof(uint8_t)) > (TC_PRIO_MAX+1))
  181. return nl_error(ERANGE, "priomap length out of bounds");
  182. for (i = 0; i <= TC_PRIO_MAX; i++) {
  183. if (priomap[i] > prio->qp_bands)
  184. return nl_error(ERANGE, "priomap element %d " \
  185. "out of bounds, increase bands number");
  186. }
  187. memcpy(prio->qp_priomap, priomap, len);
  188. prio->qp_mask |= SCH_PRIO_ATTR_PRIOMAP;
  189. return 0;
  190. }
  191. /**
  192. * Get priomap of a PRIO qdisc.
  193. * @arg qdisc PRIO qdisc.
  194. * @return Priority mapping as array of size TC_PRIO_MAX+1
  195. * or NULL if an error occured.
  196. */
  197. uint8_t *rtnl_qdisc_prio_get_priomap(struct rtnl_qdisc *qdisc)
  198. {
  199. struct rtnl_prio *prio;
  200. prio = prio_qdisc(qdisc);
  201. if (prio && prio->qp_mask & SCH_PRIO_ATTR_PRIOMAP)
  202. return prio->qp_priomap;
  203. else {
  204. nl_errno(ENOENT);
  205. return NULL;
  206. }
  207. }
  208. /** @} */
  209. /**
  210. * @name Priority Band Translations
  211. * @{
  212. */
  213. static struct trans_tbl prios[] = {
  214. __ADD(TC_PRIO_BESTEFFORT,besteffort)
  215. __ADD(TC_PRIO_FILLER,filler)
  216. __ADD(TC_PRIO_BULK,bulk)
  217. __ADD(TC_PRIO_INTERACTIVE_BULK,interactive_bulk)
  218. __ADD(TC_PRIO_INTERACTIVE,interactive)
  219. __ADD(TC_PRIO_CONTROL,control)
  220. };
  221. /**
  222. * Convert priority to character string.
  223. * @arg prio Priority.
  224. * @arg buf Destination buffer
  225. * @arg size Size of destination buffer.
  226. *
  227. * Converts a priority to a character string and stores the result in
  228. * the specified destination buffer.
  229. *
  230. * @return Name of priority as character string.
  231. */
  232. char * rtnl_prio2str(int prio, char *buf, size_t size)
  233. {
  234. return __type2str(prio, buf, size, prios, ARRAY_SIZE(prios));
  235. }
  236. /**
  237. * Convert character string to priority.
  238. * @arg name Name of priority.
  239. *
  240. * Converts the provided character string specifying a priority
  241. * to the corresponding numeric value.
  242. *
  243. * @return Numeric priority or a negative value if no match was found.
  244. */
  245. int rtnl_str2prio(const char *name)
  246. {
  247. return __str2type(name, prios, ARRAY_SIZE(prios));
  248. }
  249. /** @} */
  250. static struct rtnl_qdisc_ops prio_ops = {
  251. .qo_kind = "prio",
  252. .qo_msg_parser = prio_msg_parser,
  253. .qo_free_data = prio_free_data,
  254. .qo_dump[NL_DUMP_BRIEF] = prio_dump_brief,
  255. .qo_dump[NL_DUMP_FULL] = prio_dump_full,
  256. .qo_get_opts = prio_get_opts,
  257. };
  258. static struct rtnl_qdisc_ops pfifo_fast_ops = {
  259. .qo_kind = "pfifo_fast",
  260. .qo_msg_parser = prio_msg_parser,
  261. .qo_free_data = prio_free_data,
  262. .qo_dump[NL_DUMP_BRIEF] = prio_dump_brief,
  263. .qo_dump[NL_DUMP_FULL] = prio_dump_full,
  264. .qo_get_opts = prio_get_opts,
  265. };
  266. static void __init prio_init(void)
  267. {
  268. rtnl_qdisc_register(&prio_ops);
  269. rtnl_qdisc_register(&pfifo_fast_ops);
  270. }
  271. static void __exit prio_exit(void)
  272. {
  273. rtnl_qdisc_unregister(&prio_ops);
  274. rtnl_qdisc_unregister(&pfifo_fast_ops);
  275. }
  276. /** @} */