12 #include <netlink-private/netlink.h> 13 #include <netlink-private/tc.h> 14 #include <netlink/netlink.h> 15 #include <netlink/utils.h> 16 #include <netlink-private/route/tc-api.h> 17 #include <netlink/route/qdisc.h> 18 #include <netlink/route/qdisc/mqprio.h> 21 #define SCH_MQPRIO_ATTR_NUMTC (1 << 0) 22 #define SCH_MQPRIO_ATTR_PRIOMAP (1 << 1) 23 #define SCH_MQPRIO_ATTR_HW (1 << 2) 24 #define SCH_MQPRIO_ATTR_QUEUE (1 << 3) 25 #define SCH_MQPRIO_ATTR_MODE (1 << 4) 26 #define SCH_MQPRIO_ATTR_SHAPER (1 << 5) 27 #define SCH_MQPRIO_ATTR_MIN_RATE (1 << 6) 28 #define SCH_MQPRIO_ATTR_MAX_RATE (1 << 7) 31 static struct nla_policy mqprio_policy[TCA_MQPRIO_MAX + 1] = {
32 [TCA_MQPRIO_MODE] = { .
minlen =
sizeof(uint16_t) },
33 [TCA_MQPRIO_SHAPER] = { .minlen =
sizeof(uint16_t) },
34 [TCA_MQPRIO_MIN_RATE64] = { .type =
NLA_NESTED },
35 [TCA_MQPRIO_MAX_RATE64] = { .type =
NLA_NESTED },
38 static int mqprio_msg_parser(
struct rtnl_tc *tc,
void *data)
40 struct rtnl_mqprio *mqprio = data;
41 struct tc_mqprio_qopt *qopt;
45 if (tc->tc_opts->d_size <
sizeof(*qopt))
48 qopt = (
struct tc_mqprio_qopt *) tc->tc_opts->d_data;
49 mqprio->qm_num_tc = qopt->num_tc;
50 mqprio->qm_hw = qopt->hw;
51 memcpy(mqprio->qm_prio_map, qopt->prio_tc_map,
52 TC_QOPT_MAX_QUEUE *
sizeof(uint8_t));
53 memcpy(mqprio->qm_count, qopt->count,
54 TC_QOPT_MAX_QUEUE *
sizeof(uint16_t));
55 memcpy(mqprio->qm_offset, qopt->offset,
56 TC_QOPT_MAX_QUEUE *
sizeof(uint16_t));
57 mqprio->qm_mask = (SCH_MQPRIO_ATTR_NUMTC | SCH_MQPRIO_ATTR_PRIOMAP |
58 SCH_MQPRIO_ATTR_QUEUE | SCH_MQPRIO_ATTR_HW);
60 len = tc->tc_opts->d_size - NLA_ALIGN(
sizeof(*qopt));
63 struct nlattr *tb[TCA_MQPRIO_MAX + 1];
65 err =
nla_parse(tb, TCA_MQPRIO_MAX, (
struct nlattr *)
66 ((
char *) tc->tc_opts->d_data + NLA_ALIGN(
sizeof(*qopt))),
71 if (tb[TCA_MQPRIO_MODE]) {
73 mqprio->qm_mask |= SCH_MQPRIO_ATTR_MODE;
76 if (tb[TCA_MQPRIO_SHAPER]) {
77 mqprio->qm_shaper =
nla_get_u16(tb[TCA_MQPRIO_SHAPER]);
78 mqprio->qm_mask |= SCH_MQPRIO_ATTR_SHAPER;
81 if (tb[TCA_MQPRIO_MIN_RATE64]) {
84 if (
nla_type(attr) != TCA_MQPRIO_MIN_RATE64)
87 if (i >= mqprio->qm_num_tc)
93 mqprio->qm_mask |= SCH_MQPRIO_ATTR_MIN_RATE;
96 if (tb[TCA_MQPRIO_MAX_RATE64]) {
99 if (
nla_type(attr) != TCA_MQPRIO_MAX_RATE64)
102 if (i >= mqprio->qm_num_tc)
108 mqprio->qm_mask |= SCH_MQPRIO_ATTR_MAX_RATE;
115 static int mqprio_msg_fill(
struct rtnl_tc *tc,
void *data,
struct nl_msg *msg)
117 struct rtnl_mqprio *mqprio = data;
118 struct tc_mqprio_qopt qopt = { 0 };
119 struct nlattr *nest = NULL;
123 !(mqprio->qm_mask & SCH_MQPRIO_ATTR_NUMTC) ||
124 !(mqprio->qm_mask & SCH_MQPRIO_ATTR_PRIOMAP) ||
125 !(mqprio->qm_mask & SCH_MQPRIO_ATTR_QUEUE))
128 if (!(mqprio->qm_mask & SCH_MQPRIO_ATTR_HW))
131 qopt.hw = mqprio->qm_hw;
133 qopt.num_tc = mqprio->qm_num_tc;
134 memcpy(qopt.count, mqprio->qm_count, TC_QOPT_MAX_QUEUE *
sizeof(uint16_t));
135 memcpy(qopt.offset, mqprio->qm_offset, TC_QOPT_MAX_QUEUE *
sizeof(uint16_t));
136 memcpy(qopt.prio_tc_map, mqprio->qm_prio_map, TC_QOPT_MAX_QUEUE *
sizeof(uint8_t));
141 if (mqprio->qm_mask & SCH_MQPRIO_ATTR_MODE)
142 NLA_PUT_U16(msg, TCA_MQPRIO_MODE, mqprio->qm_mode);
144 if (mqprio->qm_mask & SCH_MQPRIO_ATTR_SHAPER)
145 NLA_PUT_U16(msg, TCA_MQPRIO_SHAPER, mqprio->qm_shaper);
147 if (mqprio->qm_mask & SCH_MQPRIO_ATTR_MIN_RATE) {
150 goto nla_put_failure;
152 for (i = 0; i < mqprio->qm_num_tc; i++) {
153 if (
nla_put(msg, TCA_MQPRIO_MIN_RATE64,
154 sizeof(mqprio->qm_min_rate[i]),
155 &mqprio->qm_min_rate[i]) < 0)
161 if (mqprio->qm_mask & SCH_MQPRIO_ATTR_MAX_RATE) {
164 goto nla_put_failure;
166 for (i = 0; i < mqprio->qm_num_tc; i++) {
167 if (
nla_put(msg, TCA_MQPRIO_MAX_RATE64,
168 sizeof(mqprio->qm_max_rate[i]),
169 &mqprio->qm_max_rate[i]) < 0)
186 static void mqprio_dump_line(
struct rtnl_tc *tc,
void *data,
189 struct rtnl_mqprio *mqprio = data;
192 nl_dump(p,
" num_tc %u", mqprio->qm_num_tc);
195 static void mqprio_dump_details(
struct rtnl_tc *tc,
void *data,
198 struct rtnl_mqprio *mqprio = data;
206 for (i = 0; i <= TC_QOPT_BITMASK; i++)
207 nl_dump(p,
"%u%s", mqprio->qm_prio_map[i],
208 i < TC_QOPT_BITMASK ?
" " :
"");
225 int rtnl_qdisc_mqprio_set_num_tc(
struct rtnl_qdisc *qdisc,
int num_tc)
227 struct rtnl_mqprio *mqprio;
232 mqprio->qm_num_tc = num_tc;
233 mqprio->qm_mask |= SCH_MQPRIO_ATTR_NUMTC;
242 int rtnl_qdisc_mqprio_get_num_tc(
struct rtnl_qdisc *qdisc)
244 struct rtnl_mqprio *mqprio;
249 if (mqprio->qm_mask & SCH_MQPRIO_ATTR_NUMTC)
250 return mqprio->qm_num_tc;
252 return -NLE_MISSING_ATTR;
262 int rtnl_qdisc_mqprio_set_priomap(
struct rtnl_qdisc *qdisc, uint8_t priomap[],
265 struct rtnl_mqprio *mqprio;
271 if (!(mqprio->qm_mask & SCH_MQPRIO_ATTR_NUMTC))
272 return -NLE_MISSING_ATTR;
274 if ((len /
sizeof(uint8_t)) > (TC_QOPT_BITMASK+1))
277 for (i = 0; i <= TC_QOPT_BITMASK; i++) {
278 if (priomap[i] > mqprio->qm_num_tc)
282 memcpy(mqprio->qm_prio_map, priomap, len *
sizeof(uint8_t));
283 mqprio->qm_mask |= SCH_MQPRIO_ATTR_PRIOMAP;
294 uint8_t *rtnl_qdisc_mqprio_get_priomap(
struct rtnl_qdisc *qdisc)
296 struct rtnl_mqprio *mqprio;
301 if (mqprio->qm_mask & SCH_MQPRIO_ATTR_PRIOMAP)
302 return mqprio->qm_prio_map;
313 int rtnl_qdisc_mqprio_hw_offload(
struct rtnl_qdisc *qdisc,
int offload)
315 struct rtnl_mqprio *mqprio;
323 mqprio->qm_hw = offload;
329 mqprio->qm_mask |= SCH_MQPRIO_ATTR_HW;
338 int rtnl_qdisc_mqprio_get_hw_offload(
struct rtnl_qdisc *qdisc)
340 struct rtnl_mqprio *mqprio;
345 if (mqprio->qm_mask & SCH_MQPRIO_ATTR_HW)
346 return mqprio->qm_hw;
358 int rtnl_qdisc_mqprio_set_queue(
struct rtnl_qdisc *qdisc, uint16_t count[],
359 uint16_t offset[],
int len)
361 struct rtnl_mqprio *mqprio;
366 if (!(mqprio->qm_mask & SCH_MQPRIO_ATTR_NUMTC))
367 return -NLE_MISSING_ATTR;
369 if ((len /
sizeof(uint16_t)) > TC_QOPT_MAX_QUEUE)
372 memcpy(mqprio->qm_count, count, len *
sizeof(uint16_t));
373 memcpy(mqprio->qm_offset, offset, len *
sizeof(uint16_t));
374 mqprio->qm_mask |= SCH_MQPRIO_ATTR_QUEUE;
386 int rtnl_qdisc_mqprio_get_queue(
struct rtnl_qdisc *qdisc, uint16_t *count,
389 struct rtnl_mqprio *mqprio;
394 if (!(mqprio->qm_mask & SCH_MQPRIO_ATTR_QUEUE))
395 return -NLE_MISSING_ATTR;
397 memcpy(count, mqprio->qm_count, TC_QOPT_MAX_QUEUE *
sizeof(uint16_t));
398 memcpy(offset, mqprio->qm_offset, TC_QOPT_MAX_QUEUE *
sizeof(uint16_t));
409 int rtnl_qdisc_mqprio_set_mode(
struct rtnl_qdisc *qdisc, uint16_t mode)
411 struct rtnl_mqprio *mqprio;
416 if (!(mqprio->qm_mask & SCH_MQPRIO_ATTR_HW))
417 return -NLE_MISSING_ATTR;
419 mqprio->qm_mode = mode;
420 mqprio->qm_mask |= SCH_MQPRIO_ATTR_MODE;
430 int rtnl_qdisc_mqprio_get_mode(
struct rtnl_qdisc *qdisc)
432 struct rtnl_mqprio *mqprio;
437 if (mqprio->qm_mask & SCH_MQPRIO_ATTR_MODE)
438 return mqprio->qm_mode;
440 return -NLE_MISSING_ATTR;
449 int rtnl_qdisc_mqprio_set_shaper(
struct rtnl_qdisc *qdisc, uint16_t shaper)
451 struct rtnl_mqprio *mqprio;
456 if (!(mqprio->qm_mask & SCH_MQPRIO_ATTR_HW))
457 return -NLE_MISSING_ATTR;
459 mqprio->qm_shaper = shaper;
460 mqprio->qm_mask |= SCH_MQPRIO_ATTR_SHAPER;
470 int rtnl_qdisc_mqprio_get_shaper(
struct rtnl_qdisc *qdisc)
472 struct rtnl_mqprio *mqprio;
477 if (mqprio->qm_mask & SCH_MQPRIO_ATTR_SHAPER)
478 return mqprio->qm_shaper;
480 return -NLE_MISSING_ATTR;
489 int rtnl_qdisc_mqprio_set_min_rate(
struct rtnl_qdisc *qdisc, uint64_t min[],
int len)
491 struct rtnl_mqprio *mqprio;
496 if (!(mqprio->qm_mask & SCH_MQPRIO_ATTR_SHAPER))
497 return -NLE_MISSING_ATTR;
499 if (mqprio->qm_shaper != TC_MQPRIO_SHAPER_BW_RATE)
502 if ((len /
sizeof(uint64_t)) > TC_QOPT_MAX_QUEUE)
505 memcpy(mqprio->qm_min_rate, min, len *
sizeof(uint64_t));
506 mqprio->qm_mask |= SCH_MQPRIO_ATTR_MIN_RATE;
517 int rtnl_qdisc_mqprio_get_min_rate(
struct rtnl_qdisc *qdisc, uint64_t *min)
519 struct rtnl_mqprio *mqprio;
524 if (mqprio->qm_mask & SCH_MQPRIO_ATTR_MIN_RATE) {
525 memcpy(min, mqprio->qm_min_rate, TC_QOPT_MAX_QUEUE *
sizeof(uint64_t));
529 return -NLE_MISSING_ATTR;
538 int rtnl_qdisc_mqprio_set_max_rate(
struct rtnl_qdisc *qdisc, uint64_t max[],
int len)
540 struct rtnl_mqprio *mqprio;
545 if (!(mqprio->qm_mask & SCH_MQPRIO_ATTR_SHAPER))
546 return -NLE_MISSING_ATTR;
548 if (mqprio->qm_shaper != TC_MQPRIO_SHAPER_BW_RATE)
551 if ((len /
sizeof(uint64_t)) > TC_QOPT_MAX_QUEUE)
554 memcpy(mqprio->qm_max_rate, max, len *
sizeof(uint64_t));
555 mqprio->qm_mask |= SCH_MQPRIO_ATTR_MAX_RATE;
566 int rtnl_qdisc_mqprio_get_max_rate(
struct rtnl_qdisc *qdisc, uint64_t *max)
568 struct rtnl_mqprio *mqprio;
573 if (mqprio->qm_mask & SCH_MQPRIO_ATTR_MAX_RATE) {
574 memcpy(max, mqprio->qm_max_rate, TC_QOPT_MAX_QUEUE *
sizeof(uint64_t));
578 return -NLE_MISSING_ATTR;
583 static struct rtnl_tc_ops mqprio_ops = {
585 .to_type = RTNL_TC_TYPE_QDISC,
586 .to_size =
sizeof(
struct rtnl_mqprio),
587 .to_msg_parser = mqprio_msg_parser,
592 .to_msg_fill = mqprio_msg_fill,
595 static void __init mqprio_init(
void)
600 static void __exit mqprio_exit(
void)
Dump object briefly on one line.
int rtnl_tc_register(struct rtnl_tc_ops *ops)
Register a traffic control module.
void nl_new_line(struct nl_dump_params *params)
Handle a new line while dumping.
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.
Attribute validation policy.
Dump all attributes but no statistics.
int nla_nest_end(struct nl_msg *msg, struct nlattr *start)
Finalize nesting of attributes.
void rtnl_tc_unregister(struct rtnl_tc_ops *ops)
Unregister a traffic control module.
#define TC_CAST(ptr)
Macro to cast qdisc/class/classifier to tc object.
int nla_type(const struct nlattr *nla)
Return type of the attribute.
uint16_t minlen
Minimal length of payload required.
#define nla_for_each_nested(pos, nla, rem)
Iterate over a stream of nested attributes.
void * rtnl_tc_data(struct rtnl_tc *tc)
Return pointer to private data of traffic control object.
int nlmsg_append(struct nl_msg *n, void *data, size_t len, int pad)
Append data to tail of a netlink message.
void nla_nest_cancel(struct nl_msg *msg, const struct nlattr *attr)
Cancel the addition of a nested attribute.
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.
uint64_t nla_get_u64(const struct nlattr *nla)
Return payload of u64 attribute.
void nl_dump(struct nl_dump_params *params, const char *fmt,...)
Dump a formatted character string.
void * rtnl_tc_data_peek(struct rtnl_tc *tc)
Returns the private data of the traffic control object.
int nla_put(struct nl_msg *msg, int attrtype, int datalen, const void *data)
Add a unspecific attribute to netlink message.
struct nlattr * nla_nest_start(struct nl_msg *msg, int attrtype)
Start a new level of nested attributes.