oops
[libnl.git] / lib / route / sch / cbq.c
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-2006 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
26  * @ingroup class
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  */
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  */
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
76 static inline struct rtnl_cbq *cbq_qdisc(struct rtnl_tca *tca)
77 {
78         return (struct rtnl_cbq *) tca->tc_subdata;
79 }
80
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
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 nl_errno(ENOMEM);
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
116 static int cbq_qdisc_msg_parser(struct rtnl_qdisc *qdisc)
117 {
118         return cbq_msg_parser((struct rtnl_tca *) qdisc);
119 }
120
121 static int cbq_class_msg_parser(struct rtnl_class *class)
122 {
123         return cbq_msg_parser((struct rtnl_tca *) class);
124 }
125
126 static void cbq_qdisc_free_data(struct rtnl_qdisc *qdisc)
127 {
128         free(qdisc->q_subdata);
129 }
130
131 static void cbq_class_free_data(struct rtnl_class *class)
132 {
133         free(class->c_subdata);
134 }
135
136 static int cbq_dump_brief(struct rtnl_tca *tca, struct nl_dump_params *p,
137                           int line)
138 {
139         struct rtnl_cbq *cbq;
140         double r, rbit;
141         char *ru, *rubit;
142
143         cbq = cbq_qdisc(tca);
144         if (!cbq)
145                 goto ignore;
146
147         r = nl_cancel_down_bytes(cbq->cbq_rate.rate, &ru);
148         rbit = nl_cancel_down_bits(cbq->cbq_rate.rate * 8, &rubit);
149
150         dp_dump(p, " rate %.2f%s/s (%.0f%s) prio %u",
151                 r, ru, rbit, rubit, cbq->cbq_wrr.priority);
152
153 ignore:
154         return line;
155 }
156
157 static int cbq_qdisc_dump_brief(struct rtnl_qdisc *qdisc,
158                                 struct nl_dump_params *p, int line)
159 {
160         return cbq_dump_brief((struct rtnl_tca *) qdisc, p, line);
161 }
162
163 static int cbq_class_dump_brief(struct rtnl_class *class,
164                                 struct nl_dump_params *p, int line)
165 {
166         return cbq_dump_brief((struct rtnl_tca *) class, p, line);
167 }
168
169 static int cbq_dump_full(struct rtnl_tca *tca, struct nl_dump_params *p,
170                          int line)
171 {
172         struct rtnl_cbq *cbq;
173         char *unit, buf[32];
174         double w;
175         uint32_t el;
176
177         cbq = cbq_qdisc(tca);
178         if (!cbq)
179                 goto ignore;
180
181         w = nl_cancel_down_bits(cbq->cbq_wrr.weight * 8, &unit);
182
183         dp_dump(p, "avgpkt %u mpu %u cell %u allot %u weight %.0f%s\n",
184                 cbq->cbq_lss.avpkt,
185                 cbq->cbq_rate.mpu,
186                 1 << cbq->cbq_rate.cell_log,
187                 cbq->cbq_wrr.allot, w, unit);
188
189         el = cbq->cbq_lss.ewma_log;
190         dp_dump_line(p, line++, "  minidle %uus maxidle %uus offtime "
191                                 "%uus level %u ewma_log %u\n",
192                 nl_ticks2us(cbq->cbq_lss.minidle >> el),
193                 nl_ticks2us(cbq->cbq_lss.maxidle >> el),
194                 nl_ticks2us(cbq->cbq_lss.offtime >> el),
195                 cbq->cbq_lss.level,
196                 cbq->cbq_lss.ewma_log);
197
198         dp_dump_line(p, line++, "  penalty %uus strategy %s ",
199                 nl_ticks2us(cbq->cbq_ovl.penalty),
200                 nl_ovl_strategy2str(cbq->cbq_ovl.strategy, buf, sizeof(buf)));
201
202         dp_dump(p, "split %s defmap 0x%08x ",
203                 rtnl_tc_handle2str(cbq->cbq_fopt.split, buf, sizeof(buf)),
204                 cbq->cbq_fopt.defmap);
205         
206         dp_dump(p, "police %s",
207                 nl_police2str(cbq->cbq_police.police, buf, sizeof(buf)));
208
209 ignore:
210         return line;
211 }
212
213 static int cbq_qdisc_dump_full(struct rtnl_qdisc *qdisc,
214                                struct nl_dump_params *p, int line)
215 {
216         return cbq_dump_full((struct rtnl_tca *) qdisc, p, line);
217 }
218
219 static int cbq_class_dump_full(struct rtnl_class *class,
220                                struct nl_dump_params *p, int line)
221 {
222         return cbq_dump_full((struct rtnl_tca *) class, p, line);
223 }
224
225 static int cbq_dump_with_stats(struct rtnl_tca *tca, struct nl_dump_params *p,
226                                int line)
227 {
228         struct tc_cbq_xstats *x = tca_xstats(tca);
229
230         if (!x)
231                 goto ignore;
232
233         dp_dump_line(p, line++, "            borrows    overact  "
234                                 "  avgidle  undertime\n");
235         dp_dump_line(p, line++, "         %10u %10u %10u %10u\n",
236                      x->borrows, x->overactions, x->avgidle, x->undertime);
237
238 ignore:
239         return line;
240 }
241
242 static int cbq_qdisc_dump_with_stats(struct rtnl_qdisc *qdisc,
243                                      struct nl_dump_params *p, int line)
244 {
245         return cbq_dump_with_stats((struct rtnl_tca *) qdisc, p, line);
246 }
247
248 static int cbq_class_dump_with_stats(struct rtnl_class *class,
249                                      struct nl_dump_params *p, int line)
250 {
251         return cbq_dump_with_stats((struct rtnl_tca *) class, p, line);
252 }
253
254 static struct rtnl_qdisc_ops cbq_qdisc_ops = {
255         .qo_kind                = "cbq",
256         .qo_msg_parser          = cbq_qdisc_msg_parser,
257         .qo_free_data           = cbq_qdisc_free_data,
258         .qo_dump[NL_DUMP_BRIEF] = cbq_qdisc_dump_brief,
259         .qo_dump[NL_DUMP_FULL]  = cbq_qdisc_dump_full,
260         .qo_dump[NL_DUMP_STATS] = cbq_qdisc_dump_with_stats,
261 };
262
263 static struct rtnl_class_ops cbq_class_ops = {
264         .co_kind                = "cbq",
265         .co_msg_parser          = cbq_class_msg_parser,
266         .co_free_data           = cbq_class_free_data,
267         .co_dump[NL_DUMP_BRIEF] = cbq_class_dump_brief,
268         .co_dump[NL_DUMP_FULL]  = cbq_class_dump_full,
269         .co_dump[NL_DUMP_STATS] = cbq_class_dump_with_stats,
270 };
271
272 static void __init cbq_init(void)
273 {
274         rtnl_qdisc_register(&cbq_qdisc_ops);
275         rtnl_class_register(&cbq_class_ops);
276 }
277
278 static void __exit cbq_exit(void)
279 {
280         rtnl_qdisc_unregister(&cbq_qdisc_ops);
281         rtnl_class_unregister(&cbq_class_ops);
282 }
283
284 /** @} */