libnl 1.1.4
prio.c
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/**
13 * @ingroup qdisc_api
14 * @defgroup prio (Fast) Prio
15 * @brief
16 *
17 * @par 1) Typical PRIO configuration
18 * @code
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);
21 *
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));
25 * @endcode
26 * @{
27 */
28
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>
36
37/** @cond SKIP */
38#define SCH_PRIO_ATTR_BANDS 1
39#define SCH_PRIO_ATTR_PRIOMAP 2
40/** @endcond */
41
42static inline struct rtnl_prio *prio_qdisc(struct rtnl_qdisc *qdisc)
43{
44 return (struct rtnl_prio *) qdisc->q_subdata;
45}
46
47static inline struct rtnl_prio *prio_alloc(struct rtnl_qdisc *qdisc)
48{
49 if (!qdisc->q_subdata)
50 qdisc->q_subdata = calloc(1, sizeof(struct rtnl_prio));
51
52 return prio_qdisc(qdisc);
53}
54
55static int prio_msg_parser(struct rtnl_qdisc *qdisc)
56{
57 struct rtnl_prio *prio;
58 struct tc_prio_qopt *opt;
59
60 if (qdisc->q_opts->d_size < sizeof(*opt))
61 return nl_error(EINVAL, "prio specific option size mismatch");
62
63 prio = prio_alloc(qdisc);
64 if (!prio)
65 return nl_errno(ENOMEM);
66
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);
71
72 return 0;
73}
74
75static void prio_free_data(struct rtnl_qdisc *qdisc)
76{
77 free(qdisc->q_subdata);
78}
79
80static int prio_dump_brief(struct rtnl_qdisc *qdisc,
81 struct nl_dump_params *p, int line)
82{
83 struct rtnl_prio *prio = prio_qdisc(qdisc);
84
85 if (prio)
86 dp_dump(p, " bands %u", prio->qp_bands);
87
88 return line;
89}
90
91static int prio_dump_full(struct rtnl_qdisc *qdisc,
92 struct nl_dump_params *p, int line)
93{
94 struct rtnl_prio *prio = prio_qdisc(qdisc);
95 int i, hp;
96
97 if (!prio)
98 goto ignore;
99
100 dp_dump(p, "priomap [");
101
102 for (i = 0; i <= TC_PRIO_MAX; i++)
103 dp_dump(p, "%u%s", prio->qp_priomap[i],
104 i < TC_PRIO_MAX ? " " : "");
105
106 dp_dump(p, "]\n");
107 dp_new_line(p, line++);
108
109 hp = (((TC_PRIO_MAX/2) + 1) & ~1);
110
111 for (i = 0; i < hp; i++) {
112 char a[32];
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]);
120 if (i < (hp - 1)) {
121 dp_dump(p, "\n");
122 dp_new_line(p, line++);
123 }
124 }
125 }
126
127ignore:
128 return line;
129}
130
131static struct nl_msg *prio_get_opts(struct rtnl_qdisc *qdisc)
132{
133 struct rtnl_prio *prio;
134 struct tc_prio_qopt opts;
135 struct nl_msg *msg;
136
137 prio = prio_qdisc(qdisc);
138 if (!prio ||
139 !(prio->qp_mask & SCH_PRIO_ATTR_PRIOMAP))
140 goto errout;
141
142 opts.bands = prio->qp_bands;
143 memcpy(opts.priomap, prio->qp_priomap, sizeof(opts.priomap));
144
145 msg = nlmsg_alloc();
146 if (!msg)
147 goto errout;
148
149 if (nlmsg_append(msg, &opts, sizeof(opts), NL_DONTPAD) < 0) {
150 nlmsg_free(msg);
151 goto errout;
152 }
153
154 return msg;
155errout:
156 return NULL;
157}
158
159/**
160 * @name Attribute Modification
161 * @{
162 */
163
164/**
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.
169 */
170int rtnl_qdisc_prio_set_bands(struct rtnl_qdisc *qdisc, int bands)
171{
172 struct rtnl_prio *prio;
173
174 prio = prio_alloc(qdisc);
175 if (!prio)
176 return nl_errno(ENOMEM);
177
178 prio->qp_bands = bands;
179 prio->qp_mask |= SCH_PRIO_ATTR_BANDS;
180
181 return 0;
182}
183
184/**
185 * Get number of bands of PRIO qdisc.
186 * @arg qdisc PRIO qdisc.
187 * @return Number of bands or a negative error code.
188 */
189int rtnl_qdisc_prio_get_bands(struct rtnl_qdisc *qdisc)
190{
191 struct rtnl_prio *prio;
192
193 prio = prio_qdisc(qdisc);
194 if (prio && prio->qp_mask & SCH_PRIO_ATTR_BANDS)
195 return prio->qp_bands;
196 else
197 return nl_errno(ENOMEM);
198}
199
200/**
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.
206 */
207int rtnl_qdisc_prio_set_priomap(struct rtnl_qdisc *qdisc, uint8_t priomap[],
208 int len)
209{
210 struct rtnl_prio *prio;
211 int i;
212
213 prio = prio_alloc(qdisc);
214 if (!prio)
215 return nl_errno(ENOMEM);
216
217 if (!(prio->qp_mask & SCH_PRIO_ATTR_BANDS))
218 return nl_error(EINVAL, "Set number of bands first");
219
220 if ((len / sizeof(uint8_t)) > (TC_PRIO_MAX+1))
221 return nl_error(ERANGE, "priomap length out of bounds");
222
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");
227 }
228
229 memcpy(prio->qp_priomap, priomap, len);
230 prio->qp_mask |= SCH_PRIO_ATTR_PRIOMAP;
231
232 return 0;
233}
234
235/**
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.
240 */
241uint8_t *rtnl_qdisc_prio_get_priomap(struct rtnl_qdisc *qdisc)
242{
243 struct rtnl_prio *prio;
244
245 prio = prio_qdisc(qdisc);
246 if (prio && prio->qp_mask & SCH_PRIO_ATTR_PRIOMAP)
247 return prio->qp_priomap;
248 else {
249 nl_errno(ENOENT);
250 return NULL;
251 }
252}
253
254/** @} */
255
256/**
257 * @name Priority Band Translations
258 * @{
259 */
260
261static 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)
268};
269
270/**
271 * Convert priority to character string.
272 * @arg prio Priority.
273 * @arg buf Destination buffer
274 * @arg size Size of destination buffer.
275 *
276 * Converts a priority to a character string and stores the result in
277 * the specified destination buffer.
278 *
279 * @return Name of priority as character string.
280 */
281char * rtnl_prio2str(int prio, char *buf, size_t size)
282{
283 return __type2str(prio, buf, size, prios, ARRAY_SIZE(prios));
284}
285
286/**
287 * Convert character string to priority.
288 * @arg name Name of priority.
289 *
290 * Converts the provided character string specifying a priority
291 * to the corresponding numeric value.
292 *
293 * @return Numeric priority or a negative value if no match was found.
294 */
295int rtnl_str2prio(const char *name)
296{
297 return __str2type(name, prios, ARRAY_SIZE(prios));
298}
299
300/** @} */
301
302static struct rtnl_qdisc_ops prio_ops = {
303 .qo_kind = "prio",
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,
309};
310
311static 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,
318};
319
320static void __init prio_init(void)
321{
322 rtnl_qdisc_register(&prio_ops);
323 rtnl_qdisc_register(&pfifo_fast_ops);
324}
325
326static void __exit prio_exit(void)
327{
328 rtnl_qdisc_unregister(&prio_ops);
329 rtnl_qdisc_unregister(&pfifo_fast_ops);
330}
331
332/** @} */
void nlmsg_free(struct nl_msg *n)
Free a netlink message.
Definition: msg.c:656
struct nl_msg * nlmsg_alloc(void)
Allocate a new netlink message with the default maximum payload size.
Definition: msg.c:401
int nlmsg_append(struct nl_msg *n, void *data, size_t len, int pad)
Append data to tail of a netlink message.
Definition: msg.c:549
int rtnl_qdisc_prio_get_bands(struct rtnl_qdisc *qdisc)
Get number of bands of PRIO qdisc.
Definition: prio.c:189
int rtnl_str2prio(const char *name)
Convert character string to priority.
Definition: prio.c:295
int rtnl_qdisc_prio_set_priomap(struct rtnl_qdisc *qdisc, uint8_t priomap[], int len)
Set priomap of the PRIO qdisc.
Definition: prio.c:207
int rtnl_qdisc_prio_set_bands(struct rtnl_qdisc *qdisc, int bands)
Set number of bands of PRIO qdisc.
Definition: prio.c:170
uint8_t * rtnl_qdisc_prio_get_priomap(struct rtnl_qdisc *qdisc)
Get priomap of a PRIO qdisc.
Definition: prio.c:241
char * rtnl_prio2str(int prio, char *buf, size_t size)
Convert priority to character string.
Definition: prio.c:281
int rtnl_qdisc_unregister(struct rtnl_qdisc_ops *qops)
Unregister a qdisc module.
Definition: qdisc_api.c:61
int rtnl_qdisc_register(struct rtnl_qdisc_ops *qops)
Register a qdisc module.
Definition: qdisc_api.c:40
@ NL_DUMP_FULL
Dump all attributes but no statistics.
Definition: types.h:23
@ NL_DUMP_BRIEF
Dump object in a brief one-liner.
Definition: types.h:22
Dumping parameters.
Definition: types.h:37
Qdisc Operations.
Definition: qdisc-modules.h:26
char qo_kind[32]
Kind/Name of Qdisc.
Definition: qdisc-modules.h:30