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