libnl  3.6.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 
25 static 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 
32 static 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 
109 static 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 
176 nla_put_failure:
177  return -NLE_MSGSIZE;
178 }
179 
180 static 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 
189 static 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  */
219 int 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  */
236 int 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  */
256 int 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 / sizeof(uint8_t)) > (TC_QOPT_BITMASK+1))
269  return -NLE_RANGE;
270 
271  for (i = 0; i <= TC_QOPT_BITMASK; i++) {
272  if (priomap[i] > mqprio->qm_num_tc)
273  return -NLE_RANGE;
274  }
275 
276  memcpy(mqprio->qm_prio_map, priomap, len * sizeof(uint8_t));
277  mqprio->qm_mask |= SCH_MQPRIO_ATTR_PRIOMAP;
278 
279  return 0;
280 }
281 
282 /**
283  * Get priomap of MQPRIO qdisc.
284  * @arg qdisc MQPRIO qdisc.
285  * @return Priority mapping as array of size TC_QOPT_BANDS+1
286  * or NULL if an error occured.
287  */
288 uint8_t *rtnl_qdisc_mqprio_get_priomap(struct rtnl_qdisc *qdisc)
289 {
290  struct rtnl_mqprio *mqprio;
291 
292  if (!(mqprio = rtnl_tc_data_peek(TC_CAST(qdisc))))
293  return NULL;
294 
295  if (mqprio->qm_mask & SCH_MQPRIO_ATTR_PRIOMAP)
296  return mqprio->qm_prio_map;
297  else
298  return NULL;
299 }
300 
301 /**
302  * Offload to HW or run in SW (default).
303  * @arg qdisc MQPRIO qdisc to be modified.
304  * @arg offload 1 - offload to HW, 0 - run in SW only (default).
305  * @return 0 on success or a negative error code.
306  */
307 int rtnl_qdisc_mqprio_hw_offload(struct rtnl_qdisc *qdisc, int offload)
308 {
309  struct rtnl_mqprio *mqprio;
310 
311  if (!(mqprio = rtnl_tc_data(TC_CAST(qdisc))))
312  return -NLE_NOMEM;
313 
314  switch (offload) {
315  case 0:
316  case 1:
317  mqprio->qm_hw = offload;
318  break;
319  default:
320  return -NLE_INVAL;
321  }
322 
323  mqprio->qm_mask |= SCH_MQPRIO_ATTR_HW;
324  return 0;
325 }
326 
327 /**
328  * Check whether running in HW or SW.
329  * @arg qdisc MQPRIO qdisc to be modified.
330  * @return 0 if running in SW, otherwise 1 (HW)
331  */
332 int rtnl_qdisc_mqprio_get_hw_offload(struct rtnl_qdisc *qdisc)
333 {
334  struct rtnl_mqprio *mqprio;
335 
336  if (!(mqprio = rtnl_tc_data_peek(TC_CAST(qdisc))))
337  return -NLE_INVAL;
338 
339  if (mqprio->qm_mask & SCH_MQPRIO_ATTR_HW)
340  return mqprio->qm_hw;
341 
342  return 0;
343 }
344 
345 /**
346  * Set tc queue of the MQPRIO qdisc.
347  * @arg qdisc MQPRIO qdisc to be modified.
348  * @arg count count of queue range for each traffic class
349  * @arg offset offset of queue range for each traffic class
350  * @return 0 on success or a negative error code.
351  */
352 int rtnl_qdisc_mqprio_set_queue(struct rtnl_qdisc *qdisc, uint16_t count[],
353  uint16_t offset[], int len)
354 {
355  struct rtnl_mqprio *mqprio;
356 
357  if (!(mqprio = rtnl_tc_data(TC_CAST(qdisc))))
358  return -NLE_NOMEM;
359 
360  if (!(mqprio->qm_mask & SCH_MQPRIO_ATTR_NUMTC))
361  return -NLE_MISSING_ATTR;
362 
363  if ((len / sizeof(uint16_t)) > TC_QOPT_MAX_QUEUE)
364  return -NLE_RANGE;
365 
366  memcpy(mqprio->qm_count, count, len * sizeof(uint16_t));
367  memcpy(mqprio->qm_offset, offset, len * sizeof(uint16_t));
368  mqprio->qm_mask |= SCH_MQPRIO_ATTR_QUEUE;
369 
370  return 0;
371 }
372 
373 /**
374  * Get tc queue of the MQPRIO qdisc.
375  * @arg qdisc MQPRIO qdisc to be modified.
376  * @arg count count of queue range for each traffic class
377  * @arg offset offset of queue range for each traffic class
378  * @return 0 on success or a negative error code.
379  */
380 int rtnl_qdisc_mqprio_get_queue(struct rtnl_qdisc *qdisc, uint16_t *count,
381  uint16_t *offset)
382 {
383  struct rtnl_mqprio *mqprio;
384 
385  if (!(mqprio = rtnl_tc_data_peek(TC_CAST(qdisc))))
386  return -NLE_INVAL;
387 
388  if (!(mqprio->qm_mask & SCH_MQPRIO_ATTR_QUEUE))
389  return -NLE_MISSING_ATTR;
390 
391  memcpy(count, mqprio->qm_count, TC_QOPT_MAX_QUEUE * sizeof(uint16_t));
392  memcpy(offset, mqprio->qm_offset, TC_QOPT_MAX_QUEUE * sizeof(uint16_t));
393 
394  return 0;
395 }
396 
397 /**
398  * Set mode of mqprio Qdisc
399  * @arg qdisc MQPRIO qdisc to be modified.
400  * @arg mode one of: TC_MQPRIO_MODE_DCB, TC_MQPRIO_MODE_CHANNEL
401  * @return 0 on success or a negative error code.
402  */
403 int rtnl_qdisc_mqprio_set_mode(struct rtnl_qdisc *qdisc, uint16_t mode)
404 {
405  struct rtnl_mqprio *mqprio;
406 
407  if (!(mqprio = rtnl_tc_data(TC_CAST(qdisc))))
408  return -NLE_NOMEM;
409 
410  if (!(mqprio->qm_mask & SCH_MQPRIO_ATTR_HW))
411  return -NLE_MISSING_ATTR;
412 
413  mqprio->qm_mode = mode;
414  mqprio->qm_mask |= SCH_MQPRIO_ATTR_MODE;
415 
416  return 0;
417 }
418 
419 /**
420  * Get mode of mqprio Qdisc
421  * @arg qdisc MQPRIO qdisc.
422  * @return mode on success or negative error code.
423  */
424 int rtnl_qdisc_mqprio_get_mode(struct rtnl_qdisc *qdisc)
425 {
426  struct rtnl_mqprio *mqprio;
427 
428  if (!(mqprio = rtnl_tc_data_peek(TC_CAST(qdisc))))
429  return -NLE_INVAL;
430 
431  if (mqprio->qm_mask & SCH_MQPRIO_ATTR_MODE)
432  return mqprio->qm_mode;
433  else
434  return -NLE_MISSING_ATTR;
435 }
436 
437 /**
438  * Set shaper of mqprio Qdisc
439  * @arg qdisc MQPRIO qdisc to be modified.
440  * @arg shaper one of: TC_MQPRIO_SHAPER_DCB, TC_MQPRIO_SHAPER_BW_RATE
441  * @return 0 on success or a negative error code.
442  */
443 int rtnl_qdisc_mqprio_set_shaper(struct rtnl_qdisc *qdisc, uint16_t shaper)
444 {
445  struct rtnl_mqprio *mqprio;
446 
447  if (!(mqprio = rtnl_tc_data(TC_CAST(qdisc))))
448  return -NLE_NOMEM;
449 
450  if (!(mqprio->qm_mask & SCH_MQPRIO_ATTR_HW))
451  return -NLE_MISSING_ATTR;
452 
453  mqprio->qm_shaper = shaper;
454  mqprio->qm_mask |= SCH_MQPRIO_ATTR_SHAPER;
455 
456  return 0;
457 }
458 
459 /**
460  * Get shaper of mqprio Qdisc
461  * @arg qdisc MQPRIO qdisc.
462  * @return shaper on success or negative error code.
463  */
464 int rtnl_qdisc_mqprio_get_shaper(struct rtnl_qdisc *qdisc)
465 {
466  struct rtnl_mqprio *mqprio;
467 
468  if (!(mqprio = rtnl_tc_data_peek(TC_CAST(qdisc))))
469  return -NLE_INVAL;
470 
471  if (mqprio->qm_mask & SCH_MQPRIO_ATTR_SHAPER)
472  return mqprio->qm_shaper;
473  else
474  return -NLE_MISSING_ATTR;
475 }
476 
477 /**
478  * Set minimum value of bandwidth rate limit for each traffic class
479  * @arg qdisc MQPRIO qdisc.
480  * @arg min minimum rate for each traffic class
481  * @return 0 on success or a negative error code.
482  */
483 int rtnl_qdisc_mqprio_set_min_rate(struct rtnl_qdisc *qdisc, uint64_t min[], int len)
484 {
485  struct rtnl_mqprio *mqprio;
486 
487  if (!(mqprio = rtnl_tc_data(TC_CAST(qdisc))))
488  return -NLE_NOMEM;
489 
490  if (!(mqprio->qm_mask & SCH_MQPRIO_ATTR_SHAPER))
491  return -NLE_MISSING_ATTR;
492 
493  if (mqprio->qm_shaper != TC_MQPRIO_SHAPER_BW_RATE)
494  return -NLE_INVAL;
495 
496  if ((len / sizeof(uint64_t)) > TC_QOPT_MAX_QUEUE)
497  return -NLE_RANGE;
498 
499  memcpy(mqprio->qm_min_rate, min, len * sizeof(uint64_t));
500  mqprio->qm_mask |= SCH_MQPRIO_ATTR_MIN_RATE;
501 
502  return 0;
503 }
504 
505 /**
506  * Get minimum value of bandwidth rate limit for each traffic class
507  * @arg qdisc MQPRIO qdisc.
508  * @arg min minimum rate for each traffic class
509  * @return 0 on success or a negative error code.
510  */
511 int rtnl_qdisc_mqprio_get_min_rate(struct rtnl_qdisc *qdisc, uint64_t *min)
512 {
513  struct rtnl_mqprio *mqprio;
514 
515  if (!(mqprio = rtnl_tc_data_peek(TC_CAST(qdisc))))
516  return -NLE_INVAL;
517 
518  if (mqprio->qm_mask & SCH_MQPRIO_ATTR_MIN_RATE) {
519  memcpy(min, mqprio->qm_min_rate, TC_QOPT_MAX_QUEUE * sizeof(uint64_t));
520  return 0;
521  }
522 
523  return -NLE_MISSING_ATTR;
524 }
525 
526 /**
527  * Set maximum value of bandwidth rate limit for each traffic class
528  * @arg qdisc MQPRIO qdisc.
529  * @arg max maximum rate for each traffic class
530  * @return 0 on success or a negative error code.
531  */
532 int rtnl_qdisc_mqprio_set_max_rate(struct rtnl_qdisc *qdisc, uint64_t max[], int len)
533 {
534  struct rtnl_mqprio *mqprio;
535 
536  if (!(mqprio = rtnl_tc_data(TC_CAST(qdisc))))
537  return -NLE_NOMEM;
538 
539  if (!(mqprio->qm_mask & SCH_MQPRIO_ATTR_SHAPER))
540  return -NLE_MISSING_ATTR;
541 
542  if (mqprio->qm_shaper != TC_MQPRIO_SHAPER_BW_RATE)
543  return -NLE_INVAL;
544 
545  if ((len / sizeof(uint64_t)) > TC_QOPT_MAX_QUEUE)
546  return -NLE_RANGE;
547 
548  memcpy(mqprio->qm_max_rate, max, len * sizeof(uint64_t));
549  mqprio->qm_mask |= SCH_MQPRIO_ATTR_MAX_RATE;
550 
551  return 0;
552 }
553 
554 /**
555  * Get maximum value of bandwidth rate limit for each traffic class
556  * @arg qdisc MQPRIO qdisc.
557  * @arg min maximum rate for each traffic class
558  * @return 0 on success or a negative error code.
559  */
560 int rtnl_qdisc_mqprio_get_max_rate(struct rtnl_qdisc *qdisc, uint64_t *max)
561 {
562  struct rtnl_mqprio *mqprio;
563 
564  if (!(mqprio = rtnl_tc_data_peek(TC_CAST(qdisc))))
565  return -NLE_INVAL;
566 
567  if (mqprio->qm_mask & SCH_MQPRIO_ATTR_MAX_RATE) {
568  memcpy(max, mqprio->qm_max_rate, TC_QOPT_MAX_QUEUE * sizeof(uint64_t));
569  return 0;
570  }
571 
572  return -NLE_MISSING_ATTR;
573 }
574 
575 /** @} */
576 
577 static struct rtnl_tc_ops mqprio_ops = {
578  .to_kind = "mqprio",
579  .to_type = RTNL_TC_TYPE_QDISC,
580  .to_size = sizeof(struct rtnl_mqprio),
581  .to_msg_parser = mqprio_msg_parser,
582  .to_dump = {
583  [NL_DUMP_LINE] = mqprio_dump_line,
584  [NL_DUMP_DETAILS] = mqprio_dump_details,
585  },
586  .to_msg_fill = mqprio_msg_fill,
587 };
588 
589 static void __init mqprio_init(void)
590 {
591  rtnl_tc_register(&mqprio_ops);
592 }
593 
594 static void __exit mqprio_exit(void)
595 {
596  rtnl_tc_unregister(&mqprio_ops);
597 }
598 
599 /** @} */
uint16_t nla_get_u16(const struct nlattr *nla)
Return payload of 16 bit integer attribute.
Definition: attr.c:649
#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:754
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:895
void nla_nest_cancel(struct nl_msg *msg, const struct nlattr *attr)
Cancel the addition of a nested attribute.
Definition: attr.c:987
#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:958
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(struct rtnl_tc *tc)
Return pointer to private data of traffic control object.
Definition: tc.c:1079
void * rtnl_tc_data_peek(struct rtnl_tc *tc)
Returns the private data of the traffic control object.
Definition: tc.c:1065
#define TC_CAST(ptr)
Macro to cast qdisc/class/classifier to tc object.
Definition: tc.h:50
int rtnl_tc_register(struct rtnl_tc_ops *ops)
Register a traffic control module.
Definition: tc.c:1018
void rtnl_tc_unregister(struct rtnl_tc_ops *ops)
Unregister a traffic control module.
Definition: tc.c:1052
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