1 /*
2 * lib/route/sch/cbq.c Class Based Queueing
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) 2003-2008 Thomas Graf <tgraf@suug.ch>
10 */
11
12 #include <netlink-local.h>
13 #include <netlink-tc.h>
14 #include <netlink/netlink.h>
15 #include <netlink/utils.h>
16 #include <netlink/route/qdisc.h>
17 #include <netlink/route/qdisc-modules.h>
18 #include <netlink/route/class.h>
19 #include <netlink/route/class-modules.h>
20 #include <netlink/route/link.h>
21 #include <netlink/route/sch/cbq.h>
22 #include <netlink/route/cls/police.h>
23
24 /**
25 * @ingroup qdisc_api
26 * @ingroup class_api
27 * @defgroup cbq Class Based Queueing (CBQ)
28 * @{
29 */
30
31 static struct trans_tbl ovl_strategies[] = {
32 __ADD(TC_CBQ_OVL_CLASSIC,classic)
33 __ADD(TC_CBQ_OVL_DELAY,delay)
34 __ADD(TC_CBQ_OVL_LOWPRIO,lowprio)
35 __ADD(TC_CBQ_OVL_DROP,drop)
36 __ADD(TC_CBQ_OVL_RCLASSIC,rclassic)
37 };
38
39 /**
40 * Convert a CBQ OVL strategy to a character string
41 * @arg type CBQ OVL strategy
42 * @arg buf destination buffer
43 * @arg len length of destination buffer
44 *
45 * Converts a CBQ OVL strategy to a character string and stores in the
46 * provided buffer. Returns the destination buffer or the type
47 * encoded in hex if no match was found.
48 */
nl_ovl_strategy2str(int type,char * buf,size_t len)49 char *nl_ovl_strategy2str(int type, char *buf, size_t len)
50 {
51 return __type2str(type, buf, len, ovl_strategies,
52 ARRAY_SIZE(ovl_strategies));
53 }
54
55 /**
56 * Convert a string to a CBQ OVL strategy
57 * @arg name CBQ OVL stragegy name
58 *
59 * Converts a CBQ OVL stragegy name to it's corresponding CBQ OVL strategy
60 * type. Returns the type or -1 if none was found.
61 */
nl_str2ovl_strategy(const char * name)62 int nl_str2ovl_strategy(const char *name)
63 {
64 return __str2type(name, ovl_strategies, ARRAY_SIZE(ovl_strategies));
65 }
66
67 static struct nla_policy cbq_policy[TCA_CBQ_MAX+1] = {
68 [TCA_CBQ_LSSOPT] = { .minlen = sizeof(struct tc_cbq_lssopt) },
69 [TCA_CBQ_RATE] = { .minlen = sizeof(struct tc_ratespec) },
70 [TCA_CBQ_WRROPT] = { .minlen = sizeof(struct tc_cbq_wrropt) },
71 [TCA_CBQ_OVL_STRATEGY] = { .minlen = sizeof(struct tc_cbq_ovl) },
72 [TCA_CBQ_FOPT] = { .minlen = sizeof(struct tc_cbq_fopt) },
73 [TCA_CBQ_POLICE] = { .minlen = sizeof(struct tc_cbq_police) },
74 };
75
cbq_qdisc(struct rtnl_tca * tca)76 static inline struct rtnl_cbq *cbq_qdisc(struct rtnl_tca *tca)
77 {
78 return (struct rtnl_cbq *) tca->tc_subdata;
79 }
80
cbq_alloc(struct rtnl_tca * tca)81 static inline struct rtnl_cbq *cbq_alloc(struct rtnl_tca *tca)
82 {
83 if (!tca->tc_subdata)
84 tca->tc_subdata = calloc(1, sizeof(struct rtnl_qdisc));
85
86 return cbq_qdisc(tca);
87 }
88
89
cbq_msg_parser(struct rtnl_tca * tca)90 static int cbq_msg_parser(struct rtnl_tca *tca)
91 {
92 struct nlattr *tb[TCA_CBQ_MAX + 1];
93 struct rtnl_cbq *cbq;
94 int err;
95
96 err = tca_parse(tb, TCA_CBQ_MAX, tca, cbq_policy);
97 if (err < 0)
98 return err;
99
100 cbq = cbq_alloc(tca);
101 if (!cbq)
102 return -NLE_NOMEM;
103
104 nla_memcpy(&cbq->cbq_lss, tb[TCA_CBQ_LSSOPT], sizeof(cbq->cbq_lss));
105 nla_memcpy(&cbq->cbq_rate, tb[TCA_CBQ_RATE], sizeof(cbq->cbq_rate));
106 nla_memcpy(&cbq->cbq_wrr, tb[TCA_CBQ_WRROPT], sizeof(cbq->cbq_wrr));
107 nla_memcpy(&cbq->cbq_fopt, tb[TCA_CBQ_FOPT], sizeof(cbq->cbq_fopt));
108 nla_memcpy(&cbq->cbq_ovl, tb[TCA_CBQ_OVL_STRATEGY],
109 sizeof(cbq->cbq_ovl));
110 nla_memcpy(&cbq->cbq_police, tb[TCA_CBQ_POLICE],
111 sizeof(cbq->cbq_police));
112
113 return 0;
114 }
115
cbq_qdisc_msg_parser(struct rtnl_qdisc * qdisc)116 static int cbq_qdisc_msg_parser(struct rtnl_qdisc *qdisc)
117 {
118 return cbq_msg_parser((struct rtnl_tca *) qdisc);
119 }
120
cbq_class_msg_parser(struct rtnl_class * class)121 static int cbq_class_msg_parser(struct rtnl_class *class)
122 {
123 return cbq_msg_parser((struct rtnl_tca *) class);
124 }
125
cbq_qdisc_free_data(struct rtnl_qdisc * qdisc)126 static void cbq_qdisc_free_data(struct rtnl_qdisc *qdisc)
127 {
128 free(qdisc->q_subdata);
129 }
130
cbq_clone(struct rtnl_tca * _dst,struct rtnl_tca * _src)131 static int cbq_clone(struct rtnl_tca *_dst, struct rtnl_tca *_src)
132 {
133 struct rtnl_cbq *src = cbq_qdisc(_src);
134
135 if (src && !cbq_alloc(_dst))
136 return -NLE_NOMEM;
137 else
138 return 0;
139 }
140
cbq_qdisc_clone(struct rtnl_qdisc * dst,struct rtnl_qdisc * src)141 static int cbq_qdisc_clone(struct rtnl_qdisc *dst, struct rtnl_qdisc *src)
142 {
143 return cbq_clone((struct rtnl_tca *) dst, (struct rtnl_tca *) src);
144 }
145
cbq_class_free_data(struct rtnl_class * class)146 static void cbq_class_free_data(struct rtnl_class *class)
147 {
148 free(class->c_subdata);
149 }
150
cbq_class_clone(struct rtnl_class * dst,struct rtnl_class * src)151 static int cbq_class_clone(struct rtnl_class *dst, struct rtnl_class *src)
152 {
153 return cbq_clone((struct rtnl_tca *) dst, (struct rtnl_tca *) src);
154 }
155
cbq_dump_line(struct rtnl_tca * tca,struct nl_dump_params * p)156 static void cbq_dump_line(struct rtnl_tca *tca, struct nl_dump_params *p)
157 {
158 struct rtnl_cbq *cbq;
159 double r, rbit;
160 char *ru, *rubit;
161
162 cbq = cbq_qdisc(tca);
163 if (!cbq)
164 return;
165
166 r = nl_cancel_down_bytes(cbq->cbq_rate.rate, &ru);
167 rbit = nl_cancel_down_bits(cbq->cbq_rate.rate * 8, &rubit);
168
169 nl_dump(p, " rate %.2f%s/s (%.0f%s) prio %u",
170 r, ru, rbit, rubit, cbq->cbq_wrr.priority);
171 }
172
cbq_qdisc_dump_line(struct rtnl_qdisc * qdisc,struct nl_dump_params * p)173 static void cbq_qdisc_dump_line(struct rtnl_qdisc *qdisc,
174 struct nl_dump_params *p)
175 {
176 cbq_dump_line((struct rtnl_tca *) qdisc, p);
177 }
178
cbq_class_dump_line(struct rtnl_class * class,struct nl_dump_params * p)179 static void cbq_class_dump_line(struct rtnl_class *class,
180 struct nl_dump_params *p)
181 {
182 cbq_dump_line((struct rtnl_tca *) class, p);
183 }
184
cbq_dump_details(struct rtnl_tca * tca,struct nl_dump_params * p)185 static void cbq_dump_details(struct rtnl_tca *tca, struct nl_dump_params *p)
186 {
187 struct rtnl_cbq *cbq;
188 char *unit, buf[32];
189 double w;
190 uint32_t el;
191
192 cbq = cbq_qdisc(tca);
193 if (!cbq)
194 return;
195
196 w = nl_cancel_down_bits(cbq->cbq_wrr.weight * 8, &unit);
197
198 nl_dump(p, "avgpkt %u mpu %u cell %u allot %u weight %.0f%s\n",
199 cbq->cbq_lss.avpkt,
200 cbq->cbq_rate.mpu,
201 1 << cbq->cbq_rate.cell_log,
202 cbq->cbq_wrr.allot, w, unit);
203
204 el = cbq->cbq_lss.ewma_log;
205 nl_dump_line(p, " minidle %uus maxidle %uus offtime "
206 "%uus level %u ewma_log %u\n",
207 nl_ticks2us(cbq->cbq_lss.minidle >> el),
208 nl_ticks2us(cbq->cbq_lss.maxidle >> el),
209 nl_ticks2us(cbq->cbq_lss.offtime >> el),
210 cbq->cbq_lss.level,
211 cbq->cbq_lss.ewma_log);
212
213 nl_dump_line(p, " penalty %uus strategy %s ",
214 nl_ticks2us(cbq->cbq_ovl.penalty),
215 nl_ovl_strategy2str(cbq->cbq_ovl.strategy, buf, sizeof(buf)));
216
217 nl_dump(p, "split %s defmap 0x%08x ",
218 rtnl_tc_handle2str(cbq->cbq_fopt.split, buf, sizeof(buf)),
219 cbq->cbq_fopt.defmap);
220
221 nl_dump(p, "police %s",
222 nl_police2str(cbq->cbq_police.police, buf, sizeof(buf)));
223 }
224
cbq_qdisc_dump_details(struct rtnl_qdisc * qdisc,struct nl_dump_params * p)225 static void cbq_qdisc_dump_details(struct rtnl_qdisc *qdisc,
226 struct nl_dump_params *p)
227 {
228 cbq_dump_details((struct rtnl_tca *) qdisc, p);
229 }
230
cbq_class_dump_details(struct rtnl_class * class,struct nl_dump_params * p)231 static void cbq_class_dump_details(struct rtnl_class *class,
232 struct nl_dump_params *p)
233 {
234 cbq_dump_details((struct rtnl_tca *) class, p);
235 }
236
cbq_dump_stats(struct rtnl_tca * tca,struct nl_dump_params * p)237 static void cbq_dump_stats(struct rtnl_tca *tca, struct nl_dump_params *p)
238 {
239 struct tc_cbq_xstats *x = tca_xstats(tca);
240
241 if (!x)
242 return;
243
244 nl_dump_line(p, " borrows overact "
245 " avgidle undertime\n");
246 nl_dump_line(p, " %10u %10u %10u %10u\n",
247 x->borrows, x->overactions, x->avgidle, x->undertime);
248 }
249
cbq_qdisc_dump_stats(struct rtnl_qdisc * qdisc,struct nl_dump_params * p)250 static void cbq_qdisc_dump_stats(struct rtnl_qdisc *qdisc,
251 struct nl_dump_params *p)
252 {
253 cbq_dump_stats((struct rtnl_tca *) qdisc, p);
254 }
255
cbq_class_dump_stats(struct rtnl_class * class,struct nl_dump_params * p)256 static void cbq_class_dump_stats(struct rtnl_class *class,
257 struct nl_dump_params *p)
258 {
259 cbq_dump_stats((struct rtnl_tca *) class, p);
260 }
261
262 static struct rtnl_qdisc_ops cbq_qdisc_ops = {
263 .qo_kind = "cbq",
264 .qo_msg_parser = cbq_qdisc_msg_parser,
265 .qo_free_data = cbq_qdisc_free_data,
266 .qo_clone = cbq_qdisc_clone,
267 .qo_dump = {
268 [NL_DUMP_LINE] = cbq_qdisc_dump_line,
269 [NL_DUMP_DETAILS] = cbq_qdisc_dump_details,
270 [NL_DUMP_STATS] = cbq_qdisc_dump_stats,
271 },
272 };
273
274 static struct rtnl_class_ops cbq_class_ops = {
275 .co_kind = "cbq",
276 .co_msg_parser = cbq_class_msg_parser,
277 .co_free_data = cbq_class_free_data,
278 .co_clone = cbq_class_clone,
279 .co_dump = {
280 [NL_DUMP_LINE] = cbq_class_dump_line,
281 [NL_DUMP_DETAILS] = cbq_class_dump_details,
282 [NL_DUMP_STATS] = cbq_class_dump_stats,
283 },
284 };
285
cbq_init(void)286 static void __init cbq_init(void)
287 {
288 rtnl_qdisc_register(&cbq_qdisc_ops);
289 rtnl_class_register(&cbq_class_ops);
290 }
291
cbq_exit(void)292 static void __exit cbq_exit(void)
293 {
294 rtnl_qdisc_unregister(&cbq_qdisc_ops);
295 rtnl_class_unregister(&cbq_class_ops);
296 }
297
298 /** @} */
299