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 
32 static 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 
38 static 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 
49 static 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 
85 static 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 
100 static 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 
105 static 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 
120 static void hfsc_class_dump_details(struct rtnl_tc *tc, void *data,
121  struct nl_dump_params *p)
122 {
123  return;
124 }
125 
126 static 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 
139 static 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 
165 nla_put_failure:
166  return -NLE_MSGSIZE;
167 }
168 
169 static struct rtnl_tc_ops hfsc_qdisc_ops;
170 static struct rtnl_tc_ops hfsc_class_ops;
171 
172 static 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 
177 static 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  */
196 uint32_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  */
212 int 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 
226 int 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 
240 int 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 
254 int 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 
268 int 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 
282 int 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 
296 int 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 
312 static 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 
321 static 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 
333 static void __init hfsc_init(void)
334 {
335  rtnl_tc_register(&hfsc_qdisc_ops);
336  rtnl_tc_register(&hfsc_class_ops);
337 }
338 
339 static 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
#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 * 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
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