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