libnl 3.11.0
hfsc.c
1/* SPDX-License-Identifier: LGPL-2.1-only */
2/*
3 * Copyright (c) 2014 Cong Wang <xiyou.wangcong@gmail.com>
4 */
5
6/**
7 * @ingroup qdisc
8 * @ingroup class
9 * @defgroup qdisc_hfsc Hierarchical Fair Service Curve (HFSC)
10 * @{
11 */
12
13#include "nl-default.h"
14
15#include <netlink/netlink.h>
16#include <netlink/cache.h>
17#include <netlink/utils.h>
18#include <netlink/route/qdisc.h>
19#include <netlink/route/class.h>
20#include <netlink/route/link.h>
21#include <netlink/route/qdisc/hfsc.h>
22
23#include "tc-api.h"
24
25/** @cond SKIP */
26struct rtnl_hfsc_qdisc {
27 uint32_t qh_defcls;
28 uint32_t qh_mask;
29};
30
31struct rtnl_hfsc_class {
32 struct tc_service_curve ch_rsc;
33 struct tc_service_curve ch_fsc;
34 struct tc_service_curve ch_usc;
35 uint32_t ch_mask;
36};
37
38#define SCH_HFSC_CLS_HAS_RSC 0x001
39#define SCH_HFSC_CLS_HAS_FSC 0x002
40#define SCH_HFSC_CLS_HAS_USC 0x004
41
42#define SCH_HFSC_QD_HAS_DEFCLS 0x01
43/** @endcond */
44
45static struct nla_policy hfsc_policy[TCA_HFSC_MAX + 1] = {
46 [TCA_HFSC_RSC] = { .minlen = sizeof(struct tc_service_curve) },
47 [TCA_HFSC_FSC] = { .minlen = sizeof(struct tc_service_curve) },
48 [TCA_HFSC_USC] = { .minlen = sizeof(struct tc_service_curve) },
49};
50
51static int hfsc_qdisc_msg_parser(struct rtnl_tc *tc, void *data)
52{
53 struct rtnl_hfsc_qdisc *hfsc = data;
54 struct tc_hfsc_qopt *opts;
55
56 opts = (struct tc_hfsc_qopt *) tc->tc_opts->d_data;
57 hfsc->qh_defcls = opts->defcls;
58 hfsc->qh_mask |= SCH_HFSC_QD_HAS_DEFCLS;
59 return 0;
60}
61
62static int hfsc_class_msg_parser(struct rtnl_tc *tc, void *data)
63{
64 struct nlattr *tb[TCA_HFSC_MAX + 1];
65 struct rtnl_hfsc_class *hfsc = data;
66 int err;
67
68 if ((err = tca_parse(tb, TCA_HFSC_MAX, tc, hfsc_policy)) < 0)
69 return err;
70
71 if (tb[TCA_HFSC_RSC]) {
72 struct tc_service_curve tsc;
73
74 nla_memcpy(&tsc, tb[TCA_HFSC_RSC], sizeof(tsc));
75 hfsc->ch_rsc = tsc;
76 hfsc->ch_mask |= SCH_HFSC_CLS_HAS_RSC;
77 }
78
79 if (tb[TCA_HFSC_FSC]) {
80 struct tc_service_curve tsc;
81
82 nla_memcpy(&tsc, tb[TCA_HFSC_FSC], sizeof(tsc));
83 hfsc->ch_fsc = tsc;
84 hfsc->ch_mask |= SCH_HFSC_CLS_HAS_FSC;
85 }
86
87 if (tb[TCA_HFSC_USC]) {
88 struct tc_service_curve tsc;
89
90 nla_memcpy(&tsc, tb[TCA_HFSC_USC], sizeof(tsc));
91 hfsc->ch_usc = tsc;
92 hfsc->ch_mask |= SCH_HFSC_CLS_HAS_USC;
93 }
94
95 return 0;
96}
97
98static void hfsc_qdisc_dump_line(struct rtnl_tc *tc, void *data,
99 struct nl_dump_params *p)
100{
101 struct rtnl_hfsc_qdisc *hfsc = data;
102
103 if (!hfsc)
104 return;
105
106 if (hfsc->qh_mask & SCH_HFSC_QD_HAS_DEFCLS) {
107 char buf[64];
108 nl_dump(p, " default-class %s",
109 rtnl_tc_handle2str(hfsc->qh_defcls, buf, sizeof(buf)));
110 }
111}
112
113static void hfsc_dump_tsc(struct nl_dump_params *p, struct tc_service_curve *tsc)
114{
115 nl_dump(p, " m1 %u d %u m2 %u\n", tsc->m1, tsc->d, tsc->m2);
116}
117
118static void hfsc_class_dump_line(struct rtnl_tc *tc, void *data,
119 struct nl_dump_params *p)
120{
121 struct rtnl_hfsc_class *hfsc = data;
122
123 if (!hfsc)
124 return;
125 if (hfsc->ch_mask & SCH_HFSC_CLS_HAS_RSC)
126 hfsc_dump_tsc(p, &hfsc->ch_rsc);
127 if (hfsc->ch_mask & SCH_HFSC_CLS_HAS_FSC)
128 hfsc_dump_tsc(p, &hfsc->ch_fsc);
129 if (hfsc->ch_mask & SCH_HFSC_CLS_HAS_USC)
130 hfsc_dump_tsc(p, &hfsc->ch_usc);
131}
132
133static void hfsc_class_dump_details(struct rtnl_tc *tc, void *data,
134 struct nl_dump_params *p)
135{
136 return;
137}
138
139static int hfsc_qdisc_msg_fill(struct rtnl_tc *tc, void *data,
140 struct nl_msg *msg)
141{
142 struct rtnl_hfsc_qdisc *hfsc = data;
143 struct tc_hfsc_qopt opts = {0};
144
145 if (!hfsc)
146 BUG();
147
148 opts.defcls = hfsc->qh_defcls;
149 return nlmsg_append(msg, &opts, sizeof(opts), NL_DONTPAD);
150}
151
152static int hfsc_class_msg_fill(struct rtnl_tc *tc, void *data,
153 struct nl_msg *msg)
154{
155 struct rtnl_hfsc_class *hfsc = data;
156 struct tc_service_curve tsc;
157
158 if (!hfsc)
159 BUG();
160
161 if (hfsc->ch_mask & SCH_HFSC_CLS_HAS_RSC) {
162 tsc = hfsc->ch_rsc;
163 NLA_PUT(msg, TCA_HFSC_RSC, sizeof(tsc), &tsc);
164 }
165
166 if (hfsc->ch_mask & SCH_HFSC_CLS_HAS_FSC) {
167 tsc = hfsc->ch_fsc;
168 NLA_PUT(msg, TCA_HFSC_FSC, sizeof(tsc), &tsc);
169 }
170
171 if (hfsc->ch_mask & SCH_HFSC_CLS_HAS_USC) {
172 tsc = hfsc->ch_usc;
173 NLA_PUT(msg, TCA_HFSC_USC, sizeof(tsc), &tsc);
174 }
175
176 return 0;
177
178nla_put_failure:
179 return -NLE_MSGSIZE;
180}
181
182static struct rtnl_tc_ops hfsc_qdisc_ops;
183static struct rtnl_tc_ops hfsc_class_ops;
184
185static struct rtnl_hfsc_qdisc *hfsc_qdisc_data(const struct rtnl_qdisc *qdisc, int *err)
186{
187 return rtnl_tc_data_check(TC_CAST(qdisc), &hfsc_qdisc_ops, err);
188}
189
190static struct rtnl_hfsc_class *hfsc_class_data(const struct rtnl_class *class, int *err)
191{
192 return rtnl_tc_data_check(TC_CAST(class), &hfsc_class_ops, err);
193}
194
195/**
196 * @name Attribute Modifications
197 * @{
198 */
199
200/**
201 * Return default class of HFSC qdisc
202 * @arg qdisc hfsc qdisc object
203 *
204 * Returns the classid of the class where all unclassified traffic
205 * goes to.
206 *
207 * @return classid or TC_H_UNSPEC if unspecified.
208 */
209uint32_t rtnl_qdisc_hfsc_get_defcls(const struct rtnl_qdisc *qdisc)
210{
211 struct rtnl_hfsc_qdisc *hfsc;
212
213 if ((hfsc = hfsc_qdisc_data(qdisc, NULL)) &&
214 (hfsc->qh_mask & SCH_HFSC_QD_HAS_DEFCLS))
215 return hfsc->qh_defcls;
216
217 return TC_H_UNSPEC;
218}
219
220/**
221 * Set default class of the hfsc qdisc to the specified value
222 * @arg qdisc qdisc to change
223 * @arg defcls new default class
224 */
225int rtnl_qdisc_hfsc_set_defcls(struct rtnl_qdisc *qdisc, uint32_t defcls)
226{
227 struct rtnl_hfsc_qdisc *hfsc;
228 int err;
229
230 if (!(hfsc = hfsc_qdisc_data(qdisc, &err)))
231 return err;
232
233 hfsc->qh_defcls = defcls;
234 hfsc->qh_mask |= SCH_HFSC_QD_HAS_DEFCLS;
235
236 return 0;
237}
238
239int rtnl_class_hfsc_get_rsc(const struct rtnl_class *class, struct tc_service_curve *tsc)
240{
241 struct rtnl_hfsc_class *hfsc;
242 int err = -NLE_OPNOTSUPP;
243
244 if ((hfsc = hfsc_class_data(class, &err)) &&
245 (hfsc->ch_mask & SCH_HFSC_CLS_HAS_RSC)) {
246 *tsc = hfsc->ch_rsc;
247 return 0;
248 }
249
250 return err;
251}
252
253int rtnl_class_hfsc_set_rsc(struct rtnl_class *class, const struct tc_service_curve *tsc)
254{
255 struct rtnl_hfsc_class *hfsc;
256 int err;
257
258 if (!(hfsc = hfsc_class_data(class, &err)))
259 return err;
260
261 hfsc->ch_rsc = *tsc;
262 hfsc->ch_mask |= SCH_HFSC_CLS_HAS_RSC;
263
264 return 0;
265}
266
267int rtnl_class_hfsc_get_fsc(const struct rtnl_class *class, struct tc_service_curve *tsc)
268{
269 struct rtnl_hfsc_class *hfsc;
270 int err = -NLE_OPNOTSUPP;
271
272 if ((hfsc = hfsc_class_data(class, &err)) &&
273 (hfsc->ch_mask & SCH_HFSC_CLS_HAS_FSC)) {
274 *tsc = hfsc->ch_fsc;
275 return 0;
276 }
277
278 return err;
279}
280
281int rtnl_class_hfsc_set_fsc(struct rtnl_class *class, const struct tc_service_curve *tsc)
282{
283 struct rtnl_hfsc_class *hfsc;
284 int err;
285
286 if (!(hfsc = hfsc_class_data(class, &err)))
287 return err;
288
289 hfsc->ch_fsc = *tsc;
290 hfsc->ch_mask |= SCH_HFSC_CLS_HAS_FSC;
291
292 return 0;
293}
294
295int rtnl_class_hfsc_get_usc(const struct rtnl_class *class, struct tc_service_curve *tsc)
296{
297 struct rtnl_hfsc_class *hfsc;
298 int err = -NLE_OPNOTSUPP;
299
300 if ((hfsc = hfsc_class_data(class, &err)) &&
301 (hfsc->ch_mask & SCH_HFSC_CLS_HAS_USC)) {
302 *tsc = hfsc->ch_usc;
303 return 0;
304 }
305
306 return err;
307}
308
309int rtnl_class_hfsc_set_usc(struct rtnl_class *class, const struct tc_service_curve *tsc)
310{
311 struct rtnl_hfsc_class *hfsc;
312 int err;
313
314 if (!(hfsc = hfsc_class_data(class, &err)))
315 return err;
316
317 hfsc->ch_usc = *tsc;
318 hfsc->ch_mask |= SCH_HFSC_CLS_HAS_USC;
319
320 return 0;
321}
322
323/** @} */
324
325static struct rtnl_tc_ops hfsc_qdisc_ops = {
326 .to_kind = "hfsc",
327 .to_type = RTNL_TC_TYPE_QDISC,
328 .to_size = sizeof(struct rtnl_hfsc_qdisc),
329 .to_msg_parser = hfsc_qdisc_msg_parser,
330 .to_dump[NL_DUMP_LINE] = hfsc_qdisc_dump_line,
331 .to_msg_fill = hfsc_qdisc_msg_fill,
332};
333
334static struct rtnl_tc_ops hfsc_class_ops = {
335 .to_kind = "hfsc",
336 .to_type = RTNL_TC_TYPE_CLASS,
337 .to_size = sizeof(struct rtnl_hfsc_class),
338 .to_msg_parser = hfsc_class_msg_parser,
339 .to_dump = {
340 [NL_DUMP_LINE] = hfsc_class_dump_line,
341 [NL_DUMP_DETAILS] = hfsc_class_dump_details,
342 },
343 .to_msg_fill = hfsc_class_msg_fill,
344};
345
346static void _nl_init hfsc_init(void)
347{
348 rtnl_tc_register(&hfsc_qdisc_ops);
349 rtnl_tc_register(&hfsc_class_ops);
350}
351
352static void _nl_exit hfsc_exit(void)
353{
354 rtnl_tc_unregister(&hfsc_qdisc_ops);
355 rtnl_tc_unregister(&hfsc_class_ops);
356}
357
358/** @} */
#define NLA_PUT(msg, attrtype, attrlen, data)
Add unspecific attribute to netlink message.
Definition attr.h:166
int nla_memcpy(void *dest, const struct nlattr *src, int count)
Copy attribute payload to another memory area.
Definition attr.c:355
char * rtnl_tc_handle2str(uint32_t handle, char *buf, size_t len)
Convert a traffic control handle to a character string (Reentrant).
Definition classid.c:109
int nlmsg_append(struct nl_msg *n, void *data, size_t len, int pad)
Append data to tail of a netlink message.
Definition msg.c:456
uint32_t rtnl_qdisc_hfsc_get_defcls(const struct rtnl_qdisc *qdisc)
Return default class of HFSC qdisc.
Definition hfsc.c:209
int rtnl_qdisc_hfsc_set_defcls(struct rtnl_qdisc *qdisc, uint32_t defcls)
Set default class of the hfsc qdisc to the specified value.
Definition hfsc.c:225
void * rtnl_tc_data_check(struct rtnl_tc *, struct rtnl_tc_ops *, int *)
Check traffic control object type and return private data section.
Definition tc.c:1114
#define TC_CAST(ptr)
Macro to cast qdisc/class/classifier to tc object.
Definition tc.h:50
int rtnl_tc_register(struct rtnl_tc_ops *)
Register a traffic control module.
Definition tc.c:1018
void rtnl_tc_unregister(struct rtnl_tc_ops *)
Unregister a traffic control module.
Definition tc.c:1052
void nl_dump(struct nl_dump_params *params, const char *fmt,...)
Dump a formatted character string.
Definition utils.c:1015
@ NL_DUMP_LINE
Dump object briefly on one line.
Definition types.h:20
@ NL_DUMP_DETAILS
Dump all attributes but no statistics.
Definition types.h:21
Dumping parameters.
Definition types.h:32
Attribute validation policy.
Definition attr.h:66
uint16_t minlen
Minimal length of payload required.
Definition attr.h:71
uint16_t type
Type of attribute or NLA_UNSPEC.
Definition attr.h:68