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.