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