libnl 3.7.0
mqprio.c
1/* SPDX-License-Identifier: LGPL-2.1-only */
2/*
3 * Copyright (c) 2018 Volodymyr Bendiuga <volodymyr.bendiuga@westermo.se>
4 */
5
6#include <netlink-private/netlink.h>
7#include <netlink-private/tc.h>
8#include <netlink/netlink.h>
9#include <netlink/utils.h>
10#include <netlink-private/route/tc-api.h>
11#include <netlink/route/qdisc.h>
12#include <netlink/route/qdisc/mqprio.h>
13
14/** @cond SKIP */
15#define SCH_MQPRIO_ATTR_NUMTC (1 << 0)
16#define SCH_MQPRIO_ATTR_PRIOMAP (1 << 1)
17#define SCH_MQPRIO_ATTR_HW (1 << 2)
18#define SCH_MQPRIO_ATTR_QUEUE (1 << 3)
19#define SCH_MQPRIO_ATTR_MODE (1 << 4)
20#define SCH_MQPRIO_ATTR_SHAPER (1 << 5)
21#define SCH_MQPRIO_ATTR_MIN_RATE (1 << 6)
22#define SCH_MQPRIO_ATTR_MAX_RATE (1 << 7)
23/** @endcond */
24
25static struct nla_policy mqprio_policy[TCA_MQPRIO_MAX + 1] = {
26 [TCA_MQPRIO_MODE] = { .minlen = sizeof(uint16_t) },
27 [TCA_MQPRIO_SHAPER] = { .minlen = sizeof(uint16_t) },
28 [TCA_MQPRIO_MIN_RATE64] = { .type = NLA_NESTED },
29 [TCA_MQPRIO_MAX_RATE64] = { .type = NLA_NESTED },
30};
31
32static int mqprio_msg_parser(struct rtnl_tc *tc, void *data)
33{
34 struct rtnl_mqprio *mqprio = data;
35 struct tc_mqprio_qopt *qopt;
36 struct nlattr *attr;
37 int len, rem, i, err;
38
39 if (tc->tc_opts->d_size < sizeof(*qopt))
40 return -NLE_INVAL;
41
42 qopt = (struct tc_mqprio_qopt *) tc->tc_opts->d_data;
43 mqprio->qm_num_tc = qopt->num_tc;
44 mqprio->qm_hw = qopt->hw;
45 memcpy(mqprio->qm_prio_map, qopt->prio_tc_map,
46 TC_QOPT_MAX_QUEUE * sizeof(uint8_t));
47 memcpy(mqprio->qm_count, qopt->count,
48 TC_QOPT_MAX_QUEUE * sizeof(uint16_t));
49 memcpy(mqprio->qm_offset, qopt->offset,
50 TC_QOPT_MAX_QUEUE * sizeof(uint16_t));
51 mqprio->qm_mask = (SCH_MQPRIO_ATTR_NUMTC | SCH_MQPRIO_ATTR_PRIOMAP |
52 SCH_MQPRIO_ATTR_QUEUE | SCH_MQPRIO_ATTR_HW);
53
54 len = tc->tc_opts->d_size - NLA_ALIGN(sizeof(*qopt));
55
56 if (len > 0) {
57 struct nlattr *tb[TCA_MQPRIO_MAX + 1];
58
59 err = nla_parse(tb, TCA_MQPRIO_MAX, (struct nlattr *)
60 ((char *) tc->tc_opts->d_data + NLA_ALIGN(sizeof(*qopt))),
61 len, mqprio_policy);
62 if (err < 0)
63 return err;
64
65 if (tb[TCA_MQPRIO_MODE]) {
66 mqprio->qm_mode = nla_get_u16(tb[TCA_MQPRIO_MODE]);
67 mqprio->qm_mask |= SCH_MQPRIO_ATTR_MODE;
68 }
69
70 if (tb[TCA_MQPRIO_SHAPER]) {
71 mqprio->qm_shaper = nla_get_u16(tb[TCA_MQPRIO_SHAPER]);
72 mqprio->qm_mask |= SCH_MQPRIO_ATTR_SHAPER;
73 }
74
75 if (tb[TCA_MQPRIO_MIN_RATE64]) {
76 i = 0;
77 nla_for_each_nested(attr, tb[TCA_MQPRIO_MIN_RATE64], rem) {
78 if (nla_type(attr) != TCA_MQPRIO_MIN_RATE64)
79 return -EINVAL;
80
81 if (i >= mqprio->qm_num_tc)
82 break;
83
84 mqprio->qm_min_rate[i] = nla_get_u64(attr);
85 }
86
87 mqprio->qm_mask |= SCH_MQPRIO_ATTR_MIN_RATE;
88 }
89
90 if (tb[TCA_MQPRIO_MAX_RATE64]) {
91 i = 0;
92 nla_for_each_nested(attr, tb[TCA_MQPRIO_MAX_RATE64], rem) {
93 if (nla_type(attr) != TCA_MQPRIO_MAX_RATE64)
94 return -EINVAL;
95
96 if (i >= mqprio->qm_num_tc)
97 break;
98
99 mqprio->qm_max_rate[i] = nla_get_u64(attr);
100 }
101
102 mqprio->qm_mask |= SCH_MQPRIO_ATTR_MAX_RATE;
103 }
104 }
105
106 return 0;
107}
108
109static int mqprio_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
110{
111 struct rtnl_mqprio *mqprio = data;
112 struct tc_mqprio_qopt qopt = { 0 };
113 struct nlattr *nest = NULL;
114 int i;
115
116 if (!mqprio ||
117 !(mqprio->qm_mask & SCH_MQPRIO_ATTR_NUMTC) ||
118 !(mqprio->qm_mask & SCH_MQPRIO_ATTR_PRIOMAP) ||
119 !(mqprio->qm_mask & SCH_MQPRIO_ATTR_QUEUE))
120 return -NLE_INVAL;
121
122 if (!(mqprio->qm_mask & SCH_MQPRIO_ATTR_HW))
123 qopt.hw = 0;
124 else
125 qopt.hw = mqprio->qm_hw;
126
127 qopt.num_tc = mqprio->qm_num_tc;
128 memcpy(qopt.count, mqprio->qm_count, TC_QOPT_MAX_QUEUE * sizeof(uint16_t));
129 memcpy(qopt.offset, mqprio->qm_offset, TC_QOPT_MAX_QUEUE * sizeof(uint16_t));
130 memcpy(qopt.prio_tc_map, mqprio->qm_prio_map, TC_QOPT_MAX_QUEUE * sizeof(uint8_t));
131
132 nlmsg_append(msg, &qopt, sizeof(qopt), NL_DONTPAD);
133
134 if (mqprio->qm_hw) {
135 if (mqprio->qm_mask & SCH_MQPRIO_ATTR_MODE)
136 NLA_PUT_U16(msg, TCA_MQPRIO_MODE, mqprio->qm_mode);
137
138 if (mqprio->qm_mask & SCH_MQPRIO_ATTR_SHAPER)
139 NLA_PUT_U16(msg, TCA_MQPRIO_SHAPER, mqprio->qm_shaper);
140
141 if (mqprio->qm_mask & SCH_MQPRIO_ATTR_MIN_RATE) {
142 nest = nla_nest_start(msg, TCA_MQPRIO_MIN_RATE64);
143 if (!nest)
144 goto nla_put_failure;
145
146 for (i = 0; i < mqprio->qm_num_tc; i++) {
147 if (nla_put(msg, TCA_MQPRIO_MIN_RATE64,
148 sizeof(mqprio->qm_min_rate[i]),
149 &mqprio->qm_min_rate[i]) < 0)
150 goto nla_nest_cancel;
151 }
152 nla_nest_end(msg, nest);
153 }
154
155 if (mqprio->qm_mask & SCH_MQPRIO_ATTR_MAX_RATE) {
156 nest = nla_nest_start(msg, TCA_MQPRIO_MAX_RATE64);
157 if (!nest)
158 goto nla_put_failure;
159
160 for (i = 0; i < mqprio->qm_num_tc; i++) {
161 if (nla_put(msg, TCA_MQPRIO_MAX_RATE64,
162 sizeof(mqprio->qm_max_rate[i]),
163 &mqprio->qm_max_rate[i]) < 0)
164 goto nla_nest_cancel;
165 }
166 nla_nest_end(msg, nest);
167 }
168 }
169
170 return 0;
171
173 nla_nest_cancel(msg, nest);
174 return -NLE_MSGSIZE;
175
176nla_put_failure:
177 return -NLE_MSGSIZE;
178}
179
180static void mqprio_dump_line(struct rtnl_tc *tc, void *data,
181 struct nl_dump_params *p)
182{
183 struct rtnl_mqprio *mqprio = data;
184
185 if (mqprio)
186 nl_dump(p, " num_tc %u", mqprio->qm_num_tc);
187}
188
189static void mqprio_dump_details(struct rtnl_tc *tc, void *data,
190 struct nl_dump_params *p)
191{
192 struct rtnl_mqprio *mqprio = data;
193 int i;
194
195 if (!mqprio)
196 return;
197
198 nl_dump(p, "map [");
199
200 for (i = 0; i <= TC_QOPT_BITMASK; i++)
201 nl_dump(p, "%u%s", mqprio->qm_prio_map[i],
202 i < TC_QOPT_BITMASK ? " " : "");
203
204 nl_dump(p, "]\n");
205 nl_new_line(p);
206}
207
208/**
209 * @name Attribute Modification
210 * @{
211 */
212
213/**
214 * Set number of traffic classes.
215 * @arg qdisc MQPRIO qdisc to be modified.
216 * @arg num_tc Number of traffic classes to create.
217 * @return 0 on success or a negative error code.
218 */
219int rtnl_qdisc_mqprio_set_num_tc(struct rtnl_qdisc *qdisc, int num_tc)
220{
221 struct rtnl_mqprio *mqprio;
222
223 if (!(mqprio = rtnl_tc_data(TC_CAST(qdisc))))
224 return -NLE_NOMEM;
225
226 mqprio->qm_num_tc = num_tc;
227 mqprio->qm_mask |= SCH_MQPRIO_ATTR_NUMTC;
228 return 0;
229}
230
231/**
232 * Get number of traffic classes of MQPRIO qdisc.
233 * @arg qdisc MQPRIO qdisc.
234 * @return Number of traffic classes or a negative error code.
235 */
236int rtnl_qdisc_mqprio_get_num_tc(struct rtnl_qdisc *qdisc)
237{
238 struct rtnl_mqprio *mqprio;
239
240 if (!(mqprio = rtnl_tc_data_peek(TC_CAST(qdisc))))
241 return -NLE_INVAL;
242
243 if (mqprio->qm_mask & SCH_MQPRIO_ATTR_NUMTC)
244 return mqprio->qm_num_tc;
245 else
246 return -NLE_MISSING_ATTR;
247}
248
249/**
250 * Set priomap of the MQPRIO qdisc.
251 * @arg qdisc MQPRIO qdisc to be modified.
252 * @arg priomap New priority mapping.
253 * @arg len Length of priomap (# of elements).
254 * @return 0 on success or a negative error code.
255 */
256int rtnl_qdisc_mqprio_set_priomap(struct rtnl_qdisc *qdisc, uint8_t priomap[],
257 int len)
258{
259 struct rtnl_mqprio *mqprio;
260 int i;
261
262 if (!(mqprio = rtnl_tc_data(TC_CAST(qdisc))))
263 return -NLE_NOMEM;
264
265 if (!(mqprio->qm_mask & SCH_MQPRIO_ATTR_NUMTC))
266 return -NLE_MISSING_ATTR;
267
268 if (len > TC_QOPT_BITMASK + 1)
269 return -NLE_RANGE;
270
271 for (i = 0; i < len; i++) {
272 if (priomap[i] > mqprio->qm_num_tc)
273 return -NLE_RANGE;
274 }
275
276 memset(mqprio->qm_prio_map, 0, sizeof(mqprio->qm_prio_map));
277 memcpy(mqprio->qm_prio_map, priomap, len * sizeof(uint8_t));
278 mqprio->qm_mask |= SCH_MQPRIO_ATTR_PRIOMAP;
279
280 return 0;
281}
282
283/**
284 * Get priomap of MQPRIO qdisc.
285 * @arg qdisc MQPRIO qdisc.
286 * @return Priority mapping as array of size TC_QOPT_BANDS+1
287 * or NULL if an error occured.
288 */
289uint8_t *rtnl_qdisc_mqprio_get_priomap(struct rtnl_qdisc *qdisc)
290{
291 struct rtnl_mqprio *mqprio;
292
293 if (!(mqprio = rtnl_tc_data_peek(TC_CAST(qdisc))))
294 return NULL;
295
296 if (mqprio->qm_mask & SCH_MQPRIO_ATTR_PRIOMAP)
297 return mqprio->qm_prio_map;
298 else
299 return NULL;
300}
301
302/**
303 * Offload to HW or run in SW (default).
304 * @arg qdisc MQPRIO qdisc to be modified.
305 * @arg offload 1 - offload to HW, 0 - run in SW only (default).
306 * @return 0 on success or a negative error code.
307 */
308int rtnl_qdisc_mqprio_hw_offload(struct rtnl_qdisc *qdisc, int offload)
309{
310 struct rtnl_mqprio *mqprio;
311
312 if (!(mqprio = rtnl_tc_data(TC_CAST(qdisc))))
313 return -NLE_NOMEM;
314
315 switch (offload) {
316 case 0:
317 case 1:
318 mqprio->qm_hw = offload;
319 break;
320 default:
321 return -NLE_INVAL;
322 }
323
324 mqprio->qm_mask |= SCH_MQPRIO_ATTR_HW;
325 return 0;
326}
327
328/**
329 * Check whether running in HW or SW.
330 * @arg qdisc MQPRIO qdisc to be modified.
331 * @return 0 if running in SW, otherwise 1 (HW)
332 */
333int rtnl_qdisc_mqprio_get_hw_offload(struct rtnl_qdisc *qdisc)
334{
335 struct rtnl_mqprio *mqprio;
336
337 if (!(mqprio = rtnl_tc_data_peek(TC_CAST(qdisc))))
338 return -NLE_INVAL;
339
340 if (mqprio->qm_mask & SCH_MQPRIO_ATTR_HW)
341 return mqprio->qm_hw;
342
343 return 0;
344}
345
346/**
347 * Set tc queue of the MQPRIO qdisc.
348 * @arg qdisc MQPRIO qdisc to be modified.
349 * @arg count count of queue range for each traffic class
350 * @arg offset offset of queue range for each traffic class
351 * @return 0 on success or a negative error code.
352 */
353int rtnl_qdisc_mqprio_set_queue(struct rtnl_qdisc *qdisc, uint16_t count[],
354 uint16_t offset[], int len)
355{
356 struct rtnl_mqprio *mqprio;
357
358 if (!(mqprio = rtnl_tc_data(TC_CAST(qdisc))))
359 return -NLE_NOMEM;
360
361 if (!(mqprio->qm_mask & SCH_MQPRIO_ATTR_NUMTC))
362 return -NLE_MISSING_ATTR;
363
364 if (len < 0 || len > TC_QOPT_MAX_QUEUE)
365 return -NLE_RANGE;
366
367 memset(mqprio->qm_count, 0, sizeof(mqprio->qm_count));
368 memset(mqprio->qm_offset, 0, sizeof(mqprio->qm_offset));
369 memcpy(mqprio->qm_count, count, len * sizeof(uint16_t));
370 memcpy(mqprio->qm_offset, offset, len * sizeof(uint16_t));
371 mqprio->qm_mask |= SCH_MQPRIO_ATTR_QUEUE;
372
373 return 0;
374}
375
376/**
377 * Get tc queue of the MQPRIO qdisc.
378 * @arg qdisc MQPRIO qdisc to be modified.
379 * @arg count count of queue range for each traffic class
380 * @arg offset offset of queue range for each traffic class
381 * @return 0 on success or a negative error code.
382 */
383int rtnl_qdisc_mqprio_get_queue(struct rtnl_qdisc *qdisc, uint16_t *count,
384 uint16_t *offset)
385{
386 struct rtnl_mqprio *mqprio;
387
388 if (!(mqprio = rtnl_tc_data_peek(TC_CAST(qdisc))))
389 return -NLE_INVAL;
390
391 if (!(mqprio->qm_mask & SCH_MQPRIO_ATTR_QUEUE))
392 return -NLE_MISSING_ATTR;
393
394 memcpy(count, mqprio->qm_count, TC_QOPT_MAX_QUEUE * sizeof(uint16_t));
395 memcpy(offset, mqprio->qm_offset, TC_QOPT_MAX_QUEUE * sizeof(uint16_t));
396
397 return 0;
398}
399
400/**
401 * Set mode of mqprio Qdisc
402 * @arg qdisc MQPRIO qdisc to be modified.
403 * @arg mode one of: TC_MQPRIO_MODE_DCB, TC_MQPRIO_MODE_CHANNEL
404 * @return 0 on success or a negative error code.
405 */
406int rtnl_qdisc_mqprio_set_mode(struct rtnl_qdisc *qdisc, uint16_t mode)
407{
408 struct rtnl_mqprio *mqprio;
409
410 if (!(mqprio = rtnl_tc_data(TC_CAST(qdisc))))
411 return -NLE_NOMEM;
412
413 if (!(mqprio->qm_mask & SCH_MQPRIO_ATTR_HW))
414 return -NLE_MISSING_ATTR;
415
416 mqprio->qm_mode = mode;
417 mqprio->qm_mask |= SCH_MQPRIO_ATTR_MODE;
418
419 return 0;
420}
421
422/**
423 * Get mode of mqprio Qdisc
424 * @arg qdisc MQPRIO qdisc.
425 * @return mode on success or negative error code.
426 */
427int rtnl_qdisc_mqprio_get_mode(struct rtnl_qdisc *qdisc)
428{
429 struct rtnl_mqprio *mqprio;
430
431 if (!(mqprio = rtnl_tc_data_peek(TC_CAST(qdisc))))
432 return -NLE_INVAL;
433
434 if (mqprio->qm_mask & SCH_MQPRIO_ATTR_MODE)
435 return mqprio->qm_mode;
436 else
437 return -NLE_MISSING_ATTR;
438}
439
440/**
441 * Set shaper of mqprio Qdisc
442 * @arg qdisc MQPRIO qdisc to be modified.
443 * @arg shaper one of: TC_MQPRIO_SHAPER_DCB, TC_MQPRIO_SHAPER_BW_RATE
444 * @return 0 on success or a negative error code.
445 */
446int rtnl_qdisc_mqprio_set_shaper(struct rtnl_qdisc *qdisc, uint16_t shaper)
447{
448 struct rtnl_mqprio *mqprio;
449
450 if (!(mqprio = rtnl_tc_data(TC_CAST(qdisc))))
451 return -NLE_NOMEM;
452
453 if (!(mqprio->qm_mask & SCH_MQPRIO_ATTR_HW))
454 return -NLE_MISSING_ATTR;
455
456 mqprio->qm_shaper = shaper;
457 mqprio->qm_mask |= SCH_MQPRIO_ATTR_SHAPER;
458
459 return 0;
460}
461
462/**
463 * Get shaper of mqprio Qdisc
464 * @arg qdisc MQPRIO qdisc.
465 * @return shaper on success or negative error code.
466 */
467int rtnl_qdisc_mqprio_get_shaper(struct rtnl_qdisc *qdisc)
468{
469 struct rtnl_mqprio *mqprio;
470
471 if (!(mqprio = rtnl_tc_data_peek(TC_CAST(qdisc))))
472 return -NLE_INVAL;
473
474 if (mqprio->qm_mask & SCH_MQPRIO_ATTR_SHAPER)
475 return mqprio->qm_shaper;
476 else
477 return -NLE_MISSING_ATTR;
478}
479
480/**
481 * Set minimum value of bandwidth rate limit for each traffic class
482 * @arg qdisc MQPRIO qdisc.
483 * @arg min minimum rate for each traffic class
484 * @return 0 on success or a negative error code.
485 */
486int rtnl_qdisc_mqprio_set_min_rate(struct rtnl_qdisc *qdisc, uint64_t min[], int len)
487{
488 struct rtnl_mqprio *mqprio;
489
490 if (!(mqprio = rtnl_tc_data(TC_CAST(qdisc))))
491 return -NLE_NOMEM;
492
493 if (!(mqprio->qm_mask & SCH_MQPRIO_ATTR_SHAPER))
494 return -NLE_MISSING_ATTR;
495
496 if (mqprio->qm_shaper != TC_MQPRIO_SHAPER_BW_RATE)
497 return -NLE_INVAL;
498
499 if (len < 0 || len > TC_QOPT_MAX_QUEUE)
500 return -NLE_RANGE;
501
502 memset(mqprio->qm_min_rate, 0, sizeof(mqprio->qm_min_rate));
503 memcpy(mqprio->qm_min_rate, min, len * sizeof(uint64_t));
504 mqprio->qm_mask |= SCH_MQPRIO_ATTR_MIN_RATE;
505
506 return 0;
507}
508
509/**
510 * Get minimum value of bandwidth rate limit for each traffic class
511 * @arg qdisc MQPRIO qdisc.
512 * @arg min minimum rate for each traffic class
513 * @return 0 on success or a negative error code.
514 */
515int rtnl_qdisc_mqprio_get_min_rate(struct rtnl_qdisc *qdisc, uint64_t *min)
516{
517 struct rtnl_mqprio *mqprio;
518
519 if (!(mqprio = rtnl_tc_data_peek(TC_CAST(qdisc))))
520 return -NLE_INVAL;
521
522 if (mqprio->qm_mask & SCH_MQPRIO_ATTR_MIN_RATE) {
523 memcpy(min, mqprio->qm_min_rate, TC_QOPT_MAX_QUEUE * sizeof(uint64_t));
524 return 0;
525 }
526
527 return -NLE_MISSING_ATTR;
528}
529
530/**
531 * Set maximum value of bandwidth rate limit for each traffic class
532 * @arg qdisc MQPRIO qdisc.
533 * @arg max maximum rate for each traffic class
534 * @return 0 on success or a negative error code.
535 */
536int rtnl_qdisc_mqprio_set_max_rate(struct rtnl_qdisc *qdisc, uint64_t max[], int len)
537{
538 struct rtnl_mqprio *mqprio;
539
540 if (!(mqprio = rtnl_tc_data(TC_CAST(qdisc))))
541 return -NLE_NOMEM;
542
543 if (!(mqprio->qm_mask & SCH_MQPRIO_ATTR_SHAPER))
544 return -NLE_MISSING_ATTR;
545
546 if (mqprio->qm_shaper != TC_MQPRIO_SHAPER_BW_RATE)
547 return -NLE_INVAL;
548
549 if (len < 0 || len > TC_QOPT_MAX_QUEUE)
550 return -NLE_RANGE;
551
552 memset(mqprio->qm_max_rate, 0, sizeof(mqprio->qm_max_rate));
553 memcpy(mqprio->qm_max_rate, max, len * sizeof(uint64_t));
554 mqprio->qm_mask |= SCH_MQPRIO_ATTR_MAX_RATE;
555
556 return 0;
557}
558
559/**
560 * Get maximum value of bandwidth rate limit for each traffic class
561 * @arg qdisc MQPRIO qdisc.
562 * @arg min maximum rate for each traffic class
563 * @return 0 on success or a negative error code.
564 */
565int rtnl_qdisc_mqprio_get_max_rate(struct rtnl_qdisc *qdisc, uint64_t *max)
566{
567 struct rtnl_mqprio *mqprio;
568
569 if (!(mqprio = rtnl_tc_data_peek(TC_CAST(qdisc))))
570 return -NLE_INVAL;
571
572 if (mqprio->qm_mask & SCH_MQPRIO_ATTR_MAX_RATE) {
573 memcpy(max, mqprio->qm_max_rate, TC_QOPT_MAX_QUEUE * sizeof(uint64_t));
574 return 0;
575 }
576
577 return -NLE_MISSING_ATTR;
578}
579
580/** @} */
581
582static struct rtnl_tc_ops mqprio_ops = {
583 .to_kind = "mqprio",
584 .to_type = RTNL_TC_TYPE_QDISC,
585 .to_size = sizeof(struct rtnl_mqprio),
586 .to_msg_parser = mqprio_msg_parser,
587 .to_dump = {
588 [NL_DUMP_LINE] = mqprio_dump_line,
589 [NL_DUMP_DETAILS] = mqprio_dump_details,
590 },
591 .to_msg_fill = mqprio_msg_fill,
592};
593
594static void __init mqprio_init(void)
595{
596 rtnl_tc_register(&mqprio_ops);
597}
598
599static void __exit mqprio_exit(void)
600{
601 rtnl_tc_unregister(&mqprio_ops);
602}
603
604/** @} */
uint16_t nla_get_u16(const struct nlattr *nla)
Return payload of 16 bit integer attribute.
Definition: attr.c:652
#define NLA_PUT_U16(msg, attrtype, value)
Add 16 bit integer attribute to netlink message.
Definition: attr.h:212
int nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head, int len, const struct nla_policy *policy)
Create attribute index based on a stream of attributes.
Definition: attr.c:236
uint64_t nla_get_u64(const struct nlattr *nla)
Return payload of u64 attribute.
Definition: attr.c:757
int nla_type(const struct nlattr *nla)
Return type of the attribute.
Definition: attr.c:103
struct nlattr * nla_nest_start(struct nl_msg *msg, int attrtype)
Start a new level of nested attributes.
Definition: attr.c:898
void nla_nest_cancel(struct nl_msg *msg, const struct nlattr *attr)
Cancel the addition of a nested attribute.
Definition: attr.c:990
#define nla_for_each_nested(pos, nla, rem)
Iterate over a stream of nested attributes.
Definition: attr.h:324
int nla_nest_end(struct nl_msg *msg, struct nlattr *start)
Finalize nesting of attributes.
Definition: attr.c:961
int nla_put(struct nl_msg *msg, int attrtype, int datalen, const void *data)
Add a unspecific attribute to netlink message.
Definition: attr.c:493
@ NLA_NESTED
Nested attributes.
Definition: attr.h:42
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:442
void * rtnl_tc_data_peek(struct rtnl_tc *tc)
Returns the private data of the traffic control object.
Definition: tc.c:1062
#define TC_CAST(ptr)
Macro to cast qdisc/class/classifier to tc object.
Definition: tc.h:50
void * rtnl_tc_data(struct rtnl_tc *tc)
Return pointer to private data of traffic control object.
Definition: tc.c:1076
int rtnl_tc_register(struct rtnl_tc_ops *ops)
Register a traffic control module.
Definition: tc.c:1015
void rtnl_tc_unregister(struct rtnl_tc_ops *ops)
Unregister a traffic control module.
Definition: tc.c:1049
void nl_dump(struct nl_dump_params *params, const char *fmt,...)
Dump a formatted character string.
Definition: utils.c:955
void nl_new_line(struct nl_dump_params *params)
Handle a new line while dumping.
Definition: utils.c:906
@ NL_DUMP_LINE
Dump object briefly on one line.
Definition: types.h:16
@ NL_DUMP_DETAILS
Dump all attributes but no statistics.
Definition: types.h:17
Dumping parameters.
Definition: types.h:28
Attribute validation policy.
Definition: attr.h:63
uint16_t minlen
Minimal length of payload required.
Definition: attr.h:68