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>
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)
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 },
32static int mqprio_msg_parser(
struct rtnl_tc *tc,
void *data)
34 struct rtnl_mqprio *mqprio = data;
35 struct tc_mqprio_qopt *qopt;
39 if (tc->tc_opts->d_size <
sizeof(*qopt))
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);
54 len = tc->tc_opts->d_size - NLA_ALIGN(
sizeof(*qopt));
57 struct nlattr *tb[TCA_MQPRIO_MAX + 1];
59 err =
nla_parse(tb, TCA_MQPRIO_MAX, (
struct nlattr *)
60 ((
char *) tc->tc_opts->d_data + NLA_ALIGN(
sizeof(*qopt))),
65 if (tb[TCA_MQPRIO_MODE]) {
67 mqprio->qm_mask |= SCH_MQPRIO_ATTR_MODE;
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;
75 if (tb[TCA_MQPRIO_MIN_RATE64]) {
78 if (
nla_type(attr) != TCA_MQPRIO_MIN_RATE64)
81 if (i >= mqprio->qm_num_tc)
87 mqprio->qm_mask |= SCH_MQPRIO_ATTR_MIN_RATE;
90 if (tb[TCA_MQPRIO_MAX_RATE64]) {
93 if (
nla_type(attr) != TCA_MQPRIO_MAX_RATE64)
96 if (i >= mqprio->qm_num_tc)
102 mqprio->qm_mask |= SCH_MQPRIO_ATTR_MAX_RATE;
109static int mqprio_msg_fill(
struct rtnl_tc *tc,
void *data,
struct nl_msg *msg)
111 struct rtnl_mqprio *mqprio = data;
112 struct tc_mqprio_qopt qopt = { 0 };
113 struct nlattr *nest = NULL;
117 !(mqprio->qm_mask & SCH_MQPRIO_ATTR_NUMTC) ||
118 !(mqprio->qm_mask & SCH_MQPRIO_ATTR_PRIOMAP) ||
119 !(mqprio->qm_mask & SCH_MQPRIO_ATTR_QUEUE))
122 if (!(mqprio->qm_mask & SCH_MQPRIO_ATTR_HW))
125 qopt.hw = mqprio->qm_hw;
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));
135 if (mqprio->qm_mask & SCH_MQPRIO_ATTR_MODE)
136 NLA_PUT_U16(msg, TCA_MQPRIO_MODE, mqprio->qm_mode);
138 if (mqprio->qm_mask & SCH_MQPRIO_ATTR_SHAPER)
139 NLA_PUT_U16(msg, TCA_MQPRIO_SHAPER, mqprio->qm_shaper);
141 if (mqprio->qm_mask & SCH_MQPRIO_ATTR_MIN_RATE) {
144 goto nla_put_failure;
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)
155 if (mqprio->qm_mask & SCH_MQPRIO_ATTR_MAX_RATE) {
158 goto nla_put_failure;
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)
180static void mqprio_dump_line(
struct rtnl_tc *tc,
void *data,
183 struct rtnl_mqprio *mqprio = data;
186 nl_dump(p,
" num_tc %u", mqprio->qm_num_tc);
189static void mqprio_dump_details(
struct rtnl_tc *tc,
void *data,
192 struct rtnl_mqprio *mqprio = data;
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 ?
" " :
"");
219int rtnl_qdisc_mqprio_set_num_tc(
struct rtnl_qdisc *qdisc,
int num_tc)
221 struct rtnl_mqprio *mqprio;
226 mqprio->qm_num_tc = num_tc;
227 mqprio->qm_mask |= SCH_MQPRIO_ATTR_NUMTC;
236int rtnl_qdisc_mqprio_get_num_tc(
struct rtnl_qdisc *qdisc)
238 struct rtnl_mqprio *mqprio;
243 if (mqprio->qm_mask & SCH_MQPRIO_ATTR_NUMTC)
244 return mqprio->qm_num_tc;
246 return -NLE_MISSING_ATTR;
256int rtnl_qdisc_mqprio_set_priomap(
struct rtnl_qdisc *qdisc, uint8_t priomap[],
259 struct rtnl_mqprio *mqprio;
265 if (!(mqprio->qm_mask & SCH_MQPRIO_ATTR_NUMTC))
266 return -NLE_MISSING_ATTR;
268 if (len > TC_QOPT_BITMASK + 1)
271 for (i = 0; i < len; i++) {
272 if (priomap[i] > mqprio->qm_num_tc)
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;
289uint8_t *rtnl_qdisc_mqprio_get_priomap(
struct rtnl_qdisc *qdisc)
291 struct rtnl_mqprio *mqprio;
296 if (mqprio->qm_mask & SCH_MQPRIO_ATTR_PRIOMAP)
297 return mqprio->qm_prio_map;
308int rtnl_qdisc_mqprio_hw_offload(
struct rtnl_qdisc *qdisc,
int offload)
310 struct rtnl_mqprio *mqprio;
318 mqprio->qm_hw = offload;
324 mqprio->qm_mask |= SCH_MQPRIO_ATTR_HW;
333int rtnl_qdisc_mqprio_get_hw_offload(
struct rtnl_qdisc *qdisc)
335 struct rtnl_mqprio *mqprio;
340 if (mqprio->qm_mask & SCH_MQPRIO_ATTR_HW)
341 return mqprio->qm_hw;
353int rtnl_qdisc_mqprio_set_queue(
struct rtnl_qdisc *qdisc, uint16_t count[],
354 uint16_t offset[],
int len)
356 struct rtnl_mqprio *mqprio;
361 if (!(mqprio->qm_mask & SCH_MQPRIO_ATTR_NUMTC))
362 return -NLE_MISSING_ATTR;
364 if (len < 0 || len > TC_QOPT_MAX_QUEUE)
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;
383int rtnl_qdisc_mqprio_get_queue(
struct rtnl_qdisc *qdisc, uint16_t *count,
386 struct rtnl_mqprio *mqprio;
391 if (!(mqprio->qm_mask & SCH_MQPRIO_ATTR_QUEUE))
392 return -NLE_MISSING_ATTR;
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));
406int rtnl_qdisc_mqprio_set_mode(
struct rtnl_qdisc *qdisc, uint16_t mode)
408 struct rtnl_mqprio *mqprio;
413 if (!(mqprio->qm_mask & SCH_MQPRIO_ATTR_HW))
414 return -NLE_MISSING_ATTR;
416 mqprio->qm_mode = mode;
417 mqprio->qm_mask |= SCH_MQPRIO_ATTR_MODE;
427int rtnl_qdisc_mqprio_get_mode(
struct rtnl_qdisc *qdisc)
429 struct rtnl_mqprio *mqprio;
434 if (mqprio->qm_mask & SCH_MQPRIO_ATTR_MODE)
435 return mqprio->qm_mode;
437 return -NLE_MISSING_ATTR;
446int rtnl_qdisc_mqprio_set_shaper(
struct rtnl_qdisc *qdisc, uint16_t shaper)
448 struct rtnl_mqprio *mqprio;
453 if (!(mqprio->qm_mask & SCH_MQPRIO_ATTR_HW))
454 return -NLE_MISSING_ATTR;
456 mqprio->qm_shaper = shaper;
457 mqprio->qm_mask |= SCH_MQPRIO_ATTR_SHAPER;
467int rtnl_qdisc_mqprio_get_shaper(
struct rtnl_qdisc *qdisc)
469 struct rtnl_mqprio *mqprio;
474 if (mqprio->qm_mask & SCH_MQPRIO_ATTR_SHAPER)
475 return mqprio->qm_shaper;
477 return -NLE_MISSING_ATTR;
486int rtnl_qdisc_mqprio_set_min_rate(
struct rtnl_qdisc *qdisc, uint64_t min[],
int len)
488 struct rtnl_mqprio *mqprio;
493 if (!(mqprio->qm_mask & SCH_MQPRIO_ATTR_SHAPER))
494 return -NLE_MISSING_ATTR;
496 if (mqprio->qm_shaper != TC_MQPRIO_SHAPER_BW_RATE)
499 if (len < 0 || len > TC_QOPT_MAX_QUEUE)
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;
515int rtnl_qdisc_mqprio_get_min_rate(
struct rtnl_qdisc *qdisc, uint64_t *min)
517 struct rtnl_mqprio *mqprio;
522 if (mqprio->qm_mask & SCH_MQPRIO_ATTR_MIN_RATE) {
523 memcpy(min, mqprio->qm_min_rate, TC_QOPT_MAX_QUEUE *
sizeof(uint64_t));
527 return -NLE_MISSING_ATTR;
536int rtnl_qdisc_mqprio_set_max_rate(
struct rtnl_qdisc *qdisc, uint64_t max[],
int len)
538 struct rtnl_mqprio *mqprio;
543 if (!(mqprio->qm_mask & SCH_MQPRIO_ATTR_SHAPER))
544 return -NLE_MISSING_ATTR;
546 if (mqprio->qm_shaper != TC_MQPRIO_SHAPER_BW_RATE)
549 if (len < 0 || len > TC_QOPT_MAX_QUEUE)
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;
565int rtnl_qdisc_mqprio_get_max_rate(
struct rtnl_qdisc *qdisc, uint64_t *max)
567 struct rtnl_mqprio *mqprio;
572 if (mqprio->qm_mask & SCH_MQPRIO_ATTR_MAX_RATE) {
573 memcpy(max, mqprio->qm_max_rate, TC_QOPT_MAX_QUEUE *
sizeof(uint64_t));
577 return -NLE_MISSING_ATTR;
582static struct rtnl_tc_ops mqprio_ops = {
584 .to_type = RTNL_TC_TYPE_QDISC,
585 .to_size =
sizeof(
struct rtnl_mqprio),
586 .to_msg_parser = mqprio_msg_parser,
591 .to_msg_fill = mqprio_msg_fill,
594static void __init mqprio_init(
void)
599static void __exit mqprio_exit(
void)
uint16_t nla_get_u16(const struct nlattr *nla)
Return payload of 16 bit integer attribute.
#define NLA_PUT_U16(msg, attrtype, value)
Add 16 bit integer attribute to netlink message.
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.
uint64_t nla_get_u64(const struct nlattr *nla)
Return payload of u64 attribute.
int nla_type(const struct nlattr *nla)
Return type of the attribute.
struct nlattr * nla_nest_start(struct nl_msg *msg, int attrtype)
Start a new level of nested attributes.
void nla_nest_cancel(struct nl_msg *msg, const struct nlattr *attr)
Cancel the addition of a nested attribute.
#define nla_for_each_nested(pos, nla, rem)
Iterate over a stream of nested attributes.
int nla_nest_end(struct nl_msg *msg, struct nlattr *start)
Finalize nesting of attributes.
int nla_put(struct nl_msg *msg, int attrtype, int datalen, const void *data)
Add a unspecific attribute to netlink message.
@ NLA_NESTED
Nested attributes.
int nlmsg_append(struct nl_msg *n, void *data, size_t len, int pad)
Append data to tail of a netlink message.
void * rtnl_tc_data_peek(struct rtnl_tc *tc)
Returns the private data of the traffic control object.
#define TC_CAST(ptr)
Macro to cast qdisc/class/classifier to tc object.
void * rtnl_tc_data(struct rtnl_tc *tc)
Return pointer to private data of traffic control object.
int rtnl_tc_register(struct rtnl_tc_ops *ops)
Register a traffic control module.
void rtnl_tc_unregister(struct rtnl_tc_ops *ops)
Unregister a traffic control module.
void nl_dump(struct nl_dump_params *params, const char *fmt,...)
Dump a formatted character string.
void nl_new_line(struct nl_dump_params *params)
Handle a new line while dumping.
@ NL_DUMP_LINE
Dump object briefly on one line.
@ NL_DUMP_DETAILS
Dump all attributes but no statistics.
Attribute validation policy.
uint16_t minlen
Minimal length of payload required.