2 * lib/route/sch/prio.c PRIO Qdisc/Class
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
9 * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
14 * @defgroup prio (Fast) Prio
17 * @par 1) Typical PRIO configuration
19 * // Specify the maximal number of bands to be used for this PRIO qdisc.
20 * rtnl_qdisc_prio_set_bands(qdisc, QDISC_PRIO_DEFAULT_BANDS);
22 * // Provide a map assigning each priority to a band number.
23 * uint8_t map[] = QDISC_PRIO_DEFAULT_PRIOMAP;
24 * rtnl_qdisc_prio_set_priomap(qdisc, map, sizeof(map));
29 #include <netlink-local.h>
30 #include <netlink-tc.h>
31 #include <netlink/netlink.h>
32 #include <netlink/utils.h>
33 #include <netlink/route/qdisc.h>
34 #include <netlink/route/qdisc-modules.h>
35 #include <netlink/route/sch/prio.h>
38 #define SCH_PRIO_ATTR_BANDS 1
39 #define SCH_PRIO_ATTR_PRIOMAP 2
42 static inline struct rtnl_prio *prio_qdisc(struct rtnl_qdisc *qdisc)
44 return (struct rtnl_prio *) qdisc->q_subdata;
47 static inline struct rtnl_prio *prio_alloc(struct rtnl_qdisc *qdisc)
49 if (!qdisc->q_subdata)
50 qdisc->q_subdata = calloc(1, sizeof(struct rtnl_prio));
52 return prio_qdisc(qdisc);
55 static int prio_msg_parser(struct rtnl_qdisc *qdisc)
57 struct rtnl_prio *prio;
58 struct tc_prio_qopt *opt;
60 if (qdisc->q_opts->d_size < sizeof(*opt))
61 return nl_error(EINVAL, "prio specific option size mismatch");
63 prio = prio_alloc(qdisc);
65 return nl_errno(ENOMEM);
67 opt = (struct tc_prio_qopt *) qdisc->q_opts->d_data;
68 prio->qp_bands = opt->bands;
69 memcpy(prio->qp_priomap, opt->priomap, sizeof(prio->qp_priomap));
70 prio->qp_mask = (SCH_PRIO_ATTR_BANDS | SCH_PRIO_ATTR_PRIOMAP);
75 static void prio_free_data(struct rtnl_qdisc *qdisc)
77 free(qdisc->q_subdata);
80 static int prio_dump_brief(struct rtnl_qdisc *qdisc,
81 struct nl_dump_params *p, int line)
83 struct rtnl_prio *prio = prio_qdisc(qdisc);
86 dp_dump(p, " bands %u", prio->qp_bands);
91 static int prio_dump_full(struct rtnl_qdisc *qdisc,
92 struct nl_dump_params *p, int line)
94 struct rtnl_prio *prio = prio_qdisc(qdisc);
100 dp_dump(p, "priomap [");
102 for (i = 0; i <= TC_PRIO_MAX; i++)
103 dp_dump(p, "%u%s", prio->qp_priomap[i],
104 i < TC_PRIO_MAX ? " " : "");
107 dp_new_line(p, line++);
109 hp = (((TC_PRIO_MAX/2) + 1) & ~1);
111 for (i = 0; i < hp; i++) {
113 dp_dump(p, " %18s => %u",
114 rtnl_prio2str(i, a, sizeof(a)),
115 prio->qp_priomap[i]);
116 if (hp+i <= TC_PRIO_MAX) {
117 dp_dump(p, " %18s => %u",
118 rtnl_prio2str(hp+i, a, sizeof(a)),
119 prio->qp_priomap[hp+i]);
122 dp_new_line(p, line++);
131 static struct nl_msg *prio_get_opts(struct rtnl_qdisc *qdisc)
133 struct rtnl_prio *prio;
134 struct tc_prio_qopt opts;
137 prio = prio_qdisc(qdisc);
139 !(prio->qp_mask & SCH_PRIO_ATTR_PRIOMAP))
142 opts.bands = prio->qp_bands;
143 memcpy(opts.priomap, prio->qp_priomap, sizeof(opts.priomap));
145 msg = nlmsg_build_no_hdr();
149 if (nlmsg_append(msg, &opts, sizeof(opts), 0) < 0) {
160 * @name Attribute Modification
165 * Set number of bands of PRIO qdisc.
166 * @arg qdisc PRIO qdisc to be modified.
167 * @arg bands New number of bands.
168 * @return 0 on success or a negative error code.
170 int rtnl_qdisc_prio_set_bands(struct rtnl_qdisc *qdisc, int bands)
172 struct rtnl_prio *prio;
174 prio = prio_alloc(qdisc);
176 return nl_errno(ENOMEM);
178 prio->qp_bands = bands;
179 prio->qp_mask |= SCH_PRIO_ATTR_BANDS;
185 * Get number of bands of PRIO qdisc.
186 * @arg qdisc PRIO qdisc.
187 * @return Number of bands or a negative error code.
189 int rtnl_qdisc_prio_get_bands(struct rtnl_qdisc *qdisc)
191 struct rtnl_prio *prio;
193 prio = prio_qdisc(qdisc);
194 if (prio && prio->qp_mask & SCH_PRIO_ATTR_BANDS)
195 return prio->qp_bands;
197 return nl_errno(ENOMEM);
201 * Set priomap of the PRIO qdisc.
202 * @arg qdisc PRIO qdisc to be modified.
203 * @arg priomap New priority mapping.
204 * @arg len Length of priomap (# of elements).
205 * @return 0 on success or a negative error code.
207 int rtnl_qdisc_prio_set_priomap(struct rtnl_qdisc *qdisc, uint8_t priomap[],
210 struct rtnl_prio *prio;
213 prio = prio_alloc(qdisc);
215 return nl_errno(ENOMEM);
217 if (!(prio->qp_mask & SCH_PRIO_ATTR_BANDS))
218 return nl_error(EINVAL, "Set number of bands first");
220 if ((len / sizeof(uint8_t)) > (TC_PRIO_MAX+1))
221 return nl_error(ERANGE, "priomap length out of bounds");
223 for (i = 0; i <= TC_PRIO_MAX; i++) {
224 if (priomap[i] > prio->qp_bands)
225 return nl_error(ERANGE, "priomap element %d " \
226 "out of bounds, increase bands number");
229 memcpy(prio->qp_priomap, priomap, len);
230 prio->qp_mask |= SCH_PRIO_ATTR_PRIOMAP;
236 * Get priomap of a PRIO qdisc.
237 * @arg qdisc PRIO qdisc.
238 * @return Priority mapping as array of size TC_PRIO_MAX+1
239 * or NULL if an error occured.
241 uint8_t *rtnl_qdisc_prio_get_priomap(struct rtnl_qdisc *qdisc)
243 struct rtnl_prio *prio;
245 prio = prio_qdisc(qdisc);
246 if (prio && prio->qp_mask & SCH_PRIO_ATTR_PRIOMAP)
247 return prio->qp_priomap;
257 * @name Priority Band Translations
261 static struct trans_tbl prios[] = {
262 __ADD(TC_PRIO_BESTEFFORT,besteffort)
263 __ADD(TC_PRIO_FILLER,filler)
264 __ADD(TC_PRIO_BULK,bulk)
265 __ADD(TC_PRIO_INTERACTIVE_BULK,interactive_bulk)
266 __ADD(TC_PRIO_INTERACTIVE,interactive)
267 __ADD(TC_PRIO_CONTROL,control)
271 * Convert priority to character string.
272 * @arg prio Priority.
273 * @arg buf Destination buffer
274 * @arg size Size of destination buffer.
276 * Converts a priority to a character string and stores the result in
277 * the specified destination buffer.
279 * @return Name of priority as character string.
281 char * rtnl_prio2str(int prio, char *buf, size_t size)
283 return __type2str(prio, buf, size, prios, ARRAY_SIZE(prios));
287 * Convert character string to priority.
288 * @arg name Name of priority.
290 * Converts the provided character string specifying a priority
291 * to the corresponding numeric value.
293 * @return Numeric priority or a negative value if no match was found.
295 int rtnl_str2prio(const char *name)
297 return __str2type(name, prios, ARRAY_SIZE(prios));
302 static struct rtnl_qdisc_ops prio_ops = {
304 .qo_msg_parser = prio_msg_parser,
305 .qo_free_data = prio_free_data,
306 .qo_dump[NL_DUMP_BRIEF] = prio_dump_brief,
307 .qo_dump[NL_DUMP_FULL] = prio_dump_full,
308 .qo_get_opts = prio_get_opts,
311 static struct rtnl_qdisc_ops pfifo_fast_ops = {
312 .qo_kind = "pfifo_fast",
313 .qo_msg_parser = prio_msg_parser,
314 .qo_free_data = prio_free_data,
315 .qo_dump[NL_DUMP_BRIEF] = prio_dump_brief,
316 .qo_dump[NL_DUMP_FULL] = prio_dump_full,
317 .qo_get_opts = prio_get_opts,
320 static void __init prio_init(void)
322 rtnl_qdisc_register(&prio_ops);
323 rtnl_qdisc_register(&pfifo_fast_ops);
326 static void __exit prio_exit(void)
328 rtnl_qdisc_unregister(&prio_ops);
329 rtnl_qdisc_unregister(&pfifo_fast_ops);