29 #include <netlink-local.h>
30 #include <netlink-tc.h>
31 #include <netlink/netlink.h>
32 #include <netlink/utils.h>
33 #include <netlink/route/qdisc.h>
34 #include <netlink/route/qdisc-modules.h>
35 #include <netlink/route/sch/prio.h>
38 #define SCH_PRIO_ATTR_BANDS 1
39 #define SCH_PRIO_ATTR_PRIOMAP 2
42 static inline struct rtnl_prio *prio_qdisc(
struct rtnl_qdisc *qdisc)
44 return (
struct rtnl_prio *) qdisc->q_subdata;
47 static inline struct rtnl_prio *prio_alloc(
struct rtnl_qdisc *qdisc)
49 if (!qdisc->q_subdata)
50 qdisc->q_subdata = calloc(1,
sizeof(
struct rtnl_prio));
52 return prio_qdisc(qdisc);
55 static int prio_msg_parser(
struct rtnl_qdisc *qdisc)
57 struct rtnl_prio *prio;
58 struct tc_prio_qopt *opt;
60 if (qdisc->q_opts->d_size <
sizeof(*opt))
61 return nl_error(EINVAL,
"prio specific option size mismatch");
63 prio = prio_alloc(qdisc);
65 return nl_errno(ENOMEM);
67 opt = (
struct tc_prio_qopt *) qdisc->q_opts->d_data;
68 prio->qp_bands = opt->bands;
69 memcpy(prio->qp_priomap, opt->priomap,
sizeof(prio->qp_priomap));
70 prio->qp_mask = (SCH_PRIO_ATTR_BANDS | SCH_PRIO_ATTR_PRIOMAP);
75 static void prio_free_data(
struct rtnl_qdisc *qdisc)
77 free(qdisc->q_subdata);
80 static int prio_dump_brief(
struct rtnl_qdisc *qdisc,
83 struct rtnl_prio *prio = prio_qdisc(qdisc);
86 dp_dump(p,
" bands %u", prio->qp_bands);
91 static int prio_dump_full(
struct rtnl_qdisc *qdisc,
94 struct rtnl_prio *prio = prio_qdisc(qdisc);
100 dp_dump(p,
"priomap [");
102 for (i = 0; i <= TC_PRIO_MAX; i++)
103 dp_dump(p,
"%u%s", prio->qp_priomap[i],
104 i < TC_PRIO_MAX ?
" " :
"");
107 dp_new_line(p, line++);
109 hp = (((TC_PRIO_MAX/2) + 1) & ~1);
111 for (i = 0; i < hp; i++) {
113 dp_dump(p,
" %18s => %u",
115 prio->qp_priomap[i]);
116 if (hp+i <= TC_PRIO_MAX) {
117 dp_dump(p,
" %18s => %u",
119 prio->qp_priomap[hp+i]);
122 dp_new_line(p, line++);
131 static struct nl_msg *prio_get_opts(
struct rtnl_qdisc *qdisc)
133 struct rtnl_prio *prio;
134 struct tc_prio_qopt opts;
137 prio = prio_qdisc(qdisc);
139 !(prio->qp_mask & SCH_PRIO_ATTR_PRIOMAP))
142 opts.bands = prio->qp_bands;
143 memcpy(opts.priomap, prio->qp_priomap,
sizeof(opts.priomap));
149 if (
nlmsg_append(msg, &opts,
sizeof(opts), NL_DONTPAD) < 0) {
172 struct rtnl_prio *prio;
174 prio = prio_alloc(qdisc);
176 return nl_errno(ENOMEM);
178 prio->qp_bands = bands;
179 prio->qp_mask |= SCH_PRIO_ATTR_BANDS;
191 struct rtnl_prio *prio;
193 prio = prio_qdisc(qdisc);
194 if (prio && prio->qp_mask & SCH_PRIO_ATTR_BANDS)
195 return prio->qp_bands;
197 return nl_errno(ENOMEM);
210 struct rtnl_prio *prio;
213 prio = prio_alloc(qdisc);
215 return nl_errno(ENOMEM);
217 if (!(prio->qp_mask & SCH_PRIO_ATTR_BANDS))
218 return nl_error(EINVAL,
"Set number of bands first");
220 if ((len /
sizeof(uint8_t)) > (TC_PRIO_MAX+1))
221 return nl_error(ERANGE,
"priomap length out of bounds");
223 for (i = 0; i <= TC_PRIO_MAX; i++) {
224 if (priomap[i] > prio->qp_bands)
225 return nl_error(ERANGE,
"priomap element %d " \
226 "out of bounds, increase bands number");
229 memcpy(prio->qp_priomap, priomap, len);
230 prio->qp_mask |= SCH_PRIO_ATTR_PRIOMAP;
243 struct rtnl_prio *prio;
245 prio = prio_qdisc(qdisc);
246 if (prio && prio->qp_mask & SCH_PRIO_ATTR_PRIOMAP)
247 return prio->qp_priomap;
261 static struct trans_tbl prios[] = {
262 __ADD(TC_PRIO_BESTEFFORT,besteffort)
263 __ADD(TC_PRIO_FILLER,filler)
264 __ADD(TC_PRIO_BULK,bulk)
265 __ADD(TC_PRIO_INTERACTIVE_BULK,interactive_bulk)
266 __ADD(TC_PRIO_INTERACTIVE,interactive)
267 __ADD(TC_PRIO_CONTROL,control)
283 return __type2str(prio, buf, size, prios, ARRAY_SIZE(prios));
297 return __str2type(name, prios, ARRAY_SIZE(prios));
304 .qo_msg_parser = prio_msg_parser,
305 .qo_free_data = prio_free_data,
308 .qo_get_opts = prio_get_opts,
313 .qo_msg_parser = prio_msg_parser,
314 .qo_free_data = prio_free_data,
317 .qo_get_opts = prio_get_opts,
320 static void __init prio_init(
void)
326 static void __exit prio_exit(
void)
Dump object in a brief one-liner.
char qo_kind[32]
Kind/Name of Qdisc.
int rtnl_qdisc_unregister(struct rtnl_qdisc_ops *qops)
Unregister a qdisc module.
struct nl_msg * nlmsg_alloc(void)
Allocate a new netlink message with the default maximum payload size.
void nlmsg_free(struct nl_msg *n)
Free a netlink message.
char * rtnl_prio2str(int prio, char *buf, size_t size)
Convert priority to character string.
int rtnl_qdisc_prio_get_bands(struct rtnl_qdisc *qdisc)
Get number of bands of PRIO qdisc.
int rtnl_str2prio(const char *name)
Convert character string to priority.
int rtnl_qdisc_prio_set_bands(struct rtnl_qdisc *qdisc, int bands)
Set number of bands of PRIO qdisc.
int rtnl_qdisc_prio_set_priomap(struct rtnl_qdisc *qdisc, uint8_t priomap[], int len)
Set priomap of the PRIO qdisc.
int nlmsg_append(struct nl_msg *n, void *data, size_t len, int pad)
Append data to tail of a netlink message.
uint8_t * rtnl_qdisc_prio_get_priomap(struct rtnl_qdisc *qdisc)
Get priomap of a PRIO qdisc.
int rtnl_qdisc_register(struct rtnl_qdisc_ops *qops)
Register a qdisc module.
Dump all attributes but no statistics.