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 
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 > 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  */
289 uint8_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  */
308 int 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  */
333 int 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  */
353 int 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  */
383 int 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  */
406 int 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  */
427 int 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  */
446 int 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  */
467 int 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  */
486 int 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  */
515 int 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  */
536 int 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  */
565 int 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 
582 static 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 
594 static void __init mqprio_init(void)
595 {
596  rtnl_tc_register(&mqprio_ops);
597 }
598 
599 static 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: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:1076
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
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