• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3  * Copyright (c) 2003-2011 Thomas Graf <tgraf@suug.ch>
4  */
5 
6 /**
7  * @ingroup qdisc
8  * @defgroup qdisc_prio (Fast) Prio
9  * @brief
10  *
11  * @par 1) Typical PRIO configuration
12  * @code
13  * // Specify the maximal number of bands to be used for this PRIO qdisc.
14  * rtnl_qdisc_prio_set_bands(qdisc, QDISC_PRIO_DEFAULT_BANDS);
15  *
16  * // Provide a map assigning each priority to a band number.
17  * uint8_t map[] = QDISC_PRIO_DEFAULT_PRIOMAP;
18  * rtnl_qdisc_prio_set_priomap(qdisc, map, sizeof(map));
19  * @endcode
20  * @{
21  */
22 
23 #include <netlink-private/netlink.h>
24 #include <netlink-private/tc.h>
25 #include <netlink/netlink.h>
26 #include <netlink/utils.h>
27 #include <netlink-private/route/tc-api.h>
28 #include <netlink/route/qdisc.h>
29 #include <netlink/route/qdisc/prio.h>
30 
31 /** @cond SKIP */
32 #define SCH_PRIO_ATTR_BANDS	1
33 #define SCH_PRIO_ATTR_PRIOMAP	2
34 /** @endcond */
35 
prio_msg_parser(struct rtnl_tc * tc,void * data)36 static int prio_msg_parser(struct rtnl_tc *tc, void *data)
37 {
38 	struct rtnl_prio *prio = data;
39 	struct tc_prio_qopt *opt;
40 
41 	if (tc->tc_opts->d_size < sizeof(*opt))
42 		return -NLE_INVAL;
43 
44 	opt = (struct tc_prio_qopt *) tc->tc_opts->d_data;
45 	prio->qp_bands = opt->bands;
46 	memcpy(prio->qp_priomap, opt->priomap, sizeof(prio->qp_priomap));
47 	prio->qp_mask = (SCH_PRIO_ATTR_BANDS | SCH_PRIO_ATTR_PRIOMAP);
48 
49 	return 0;
50 }
51 
prio_dump_line(struct rtnl_tc * tc,void * data,struct nl_dump_params * p)52 static void prio_dump_line(struct rtnl_tc *tc, void *data,
53 			   struct nl_dump_params *p)
54 {
55 	struct rtnl_prio *prio = data;
56 
57 	if (prio)
58 		nl_dump(p, " bands %u", prio->qp_bands);
59 }
60 
prio_dump_details(struct rtnl_tc * tc,void * data,struct nl_dump_params * p)61 static void prio_dump_details(struct rtnl_tc *tc, void *data,
62 			      struct nl_dump_params *p)
63 {
64 	struct rtnl_prio *prio = data;
65 	int i, hp;
66 
67 	if (!prio)
68 		return;
69 
70 	nl_dump(p, "priomap [");
71 
72 	for (i = 0; i <= TC_PRIO_MAX; i++)
73 		nl_dump(p, "%u%s", prio->qp_priomap[i],
74 			i < TC_PRIO_MAX ? " " : "");
75 
76 	nl_dump(p, "]\n");
77 	nl_new_line(p);
78 
79 	hp = (((TC_PRIO_MAX/2) + 1) & ~1);
80 
81 	for (i = 0; i < hp; i++) {
82 		char a[32];
83 		nl_dump(p, "    %18s => %u",
84 			rtnl_prio2str(i, a, sizeof(a)),
85 			prio->qp_priomap[i]);
86 		if (hp+i <= TC_PRIO_MAX) {
87 			nl_dump(p, " %18s => %u",
88 				rtnl_prio2str(hp+i, a, sizeof(a)),
89 				prio->qp_priomap[hp+i]);
90 			if (i < (hp - 1)) {
91 				nl_dump(p, "\n");
92 				nl_new_line(p);
93 			}
94 		}
95 	}
96 }
97 
prio_msg_fill(struct rtnl_tc * tc,void * data,struct nl_msg * msg)98 static int prio_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
99 {
100 	struct rtnl_prio *prio = data;
101 	struct tc_prio_qopt opts;
102 
103 	if (!prio || !(prio->qp_mask & SCH_PRIO_ATTR_PRIOMAP))
104 		BUG();
105 
106 	opts.bands = prio->qp_bands;
107 	memcpy(opts.priomap, prio->qp_priomap, sizeof(opts.priomap));
108 
109 	return nlmsg_append(msg, &opts, sizeof(opts), NL_DONTPAD);
110 }
111 
112 /**
113  * @name Attribute Modification
114  * @{
115  */
116 
117 /**
118  * Set number of bands of PRIO qdisc.
119  * @arg qdisc		PRIO qdisc to be modified.
120  * @arg bands		New number of bands.
121  * @return 0 on success or a negative error code.
122  */
rtnl_qdisc_prio_set_bands(struct rtnl_qdisc * qdisc,int bands)123 void rtnl_qdisc_prio_set_bands(struct rtnl_qdisc *qdisc, int bands)
124 {
125 	struct rtnl_prio *prio;
126 
127 	if (!(prio = rtnl_tc_data(TC_CAST(qdisc))))
128 		BUG();
129 
130 	prio->qp_bands = bands;
131 	prio->qp_mask |= SCH_PRIO_ATTR_BANDS;
132 }
133 
134 /**
135  * Get number of bands of PRIO qdisc.
136  * @arg qdisc		PRIO qdisc.
137  * @return Number of bands or a negative error code.
138  */
rtnl_qdisc_prio_get_bands(struct rtnl_qdisc * qdisc)139 int rtnl_qdisc_prio_get_bands(struct rtnl_qdisc *qdisc)
140 {
141 	struct rtnl_prio *prio;
142 
143 	if (!(prio = rtnl_tc_data(TC_CAST(qdisc))))
144 		BUG();
145 
146 	if (prio->qp_mask & SCH_PRIO_ATTR_BANDS)
147 		return prio->qp_bands;
148 	else
149 		return -NLE_NOMEM;
150 }
151 
152 /**
153  * Set priomap of the PRIO qdisc.
154  * @arg qdisc		PRIO qdisc to be modified.
155  * @arg priomap		New priority mapping.
156  * @arg len		Length of priomap (# of elements).
157  * @return 0 on success or a negative error code.
158  */
rtnl_qdisc_prio_set_priomap(struct rtnl_qdisc * qdisc,uint8_t priomap[],int len)159 int rtnl_qdisc_prio_set_priomap(struct rtnl_qdisc *qdisc, uint8_t priomap[],
160 				int len)
161 {
162 	struct rtnl_prio *prio;
163 	int i;
164 
165 	if (!(prio = rtnl_tc_data(TC_CAST(qdisc))))
166 		BUG();
167 
168 	if (!(prio->qp_mask & SCH_PRIO_ATTR_BANDS))
169 		return -NLE_MISSING_ATTR;
170 
171 	if ((len / sizeof(uint8_t)) > (TC_PRIO_MAX+1))
172 		return -NLE_RANGE;
173 
174 	for (i = 0; i <= TC_PRIO_MAX; i++) {
175 		if (priomap[i] > prio->qp_bands)
176 			return -NLE_RANGE;
177 	}
178 
179 	memcpy(prio->qp_priomap, priomap, len);
180 	prio->qp_mask |= SCH_PRIO_ATTR_PRIOMAP;
181 
182 	return 0;
183 }
184 
185 /**
186  * Get priomap of a PRIO qdisc.
187  * @arg qdisc		PRIO qdisc.
188  * @return Priority mapping as array of size TC_PRIO_MAX+1
189  *         or NULL if an error occured.
190  */
rtnl_qdisc_prio_get_priomap(struct rtnl_qdisc * qdisc)191 uint8_t *rtnl_qdisc_prio_get_priomap(struct rtnl_qdisc *qdisc)
192 {
193 	struct rtnl_prio *prio;
194 
195 	if (!(prio = rtnl_tc_data(TC_CAST(qdisc))))
196 		BUG();
197 
198 	if (prio->qp_mask & SCH_PRIO_ATTR_PRIOMAP)
199 		return prio->qp_priomap;
200 	else
201 		return NULL;
202 }
203 
204 /** @} */
205 
206 /**
207  * @name Priority Band Translations
208  * @{
209  */
210 
211 static const struct trans_tbl prios[] = {
212 	__ADD(TC_PRIO_BESTEFFORT,besteffort),
213 	__ADD(TC_PRIO_FILLER,filler),
214 	__ADD(TC_PRIO_BULK,bulk),
215 	__ADD(TC_PRIO_INTERACTIVE_BULK,interactive_bulk),
216 	__ADD(TC_PRIO_INTERACTIVE,interactive),
217 	__ADD(TC_PRIO_CONTROL,control),
218 };
219 
220 /**
221  * Convert priority to character string.
222  * @arg prio		Priority.
223  * @arg buf		Destination buffer
224  * @arg size		Size of destination buffer.
225  *
226  * Converts a priority to a character string and stores the result in
227  * the specified destination buffer.
228  *
229  * @return Name of priority as character string.
230  */
rtnl_prio2str(int prio,char * buf,size_t size)231 char * rtnl_prio2str(int prio, char *buf, size_t size)
232 {
233 	return __type2str(prio, buf, size, prios, ARRAY_SIZE(prios));
234 }
235 
236 /**
237  * Convert character string to priority.
238  * @arg name		Name of priority.
239  *
240  * Converts the provided character string specifying a priority
241  * to the corresponding numeric value.
242  *
243  * @return Numeric priority or a negative value if no match was found.
244  */
rtnl_str2prio(const char * name)245 int rtnl_str2prio(const char *name)
246 {
247 	return __str2type(name, prios, ARRAY_SIZE(prios));
248 }
249 
250 /** @} */
251 
252 static struct rtnl_tc_ops prio_ops = {
253 	.to_kind		= "prio",
254 	.to_type		= RTNL_TC_TYPE_QDISC,
255 	.to_size		= sizeof(struct rtnl_prio),
256 	.to_msg_parser		= prio_msg_parser,
257 	.to_dump = {
258 	    [NL_DUMP_LINE]	= prio_dump_line,
259 	    [NL_DUMP_DETAILS]	= prio_dump_details,
260 	},
261 	.to_msg_fill		= prio_msg_fill,
262 };
263 
264 static struct rtnl_tc_ops pfifo_fast_ops = {
265 	.to_kind		= "pfifo_fast",
266 	.to_type		= RTNL_TC_TYPE_QDISC,
267 	.to_size		= sizeof(struct rtnl_prio),
268 	.to_msg_parser		= prio_msg_parser,
269 	.to_dump = {
270 	    [NL_DUMP_LINE]	= prio_dump_line,
271 	    [NL_DUMP_DETAILS]	= prio_dump_details,
272 	},
273 	.to_msg_fill		= prio_msg_fill,
274 };
275 
prio_init(void)276 static void __init prio_init(void)
277 {
278 	rtnl_tc_register(&prio_ops);
279 	rtnl_tc_register(&pfifo_fast_ops);
280 }
281 
prio_exit(void)282 static void __exit prio_exit(void)
283 {
284 	rtnl_tc_unregister(&prio_ops);
285 	rtnl_tc_unregister(&pfifo_fast_ops);
286 }
287 
288 /** @} */
289