Tizen 2.1 base
[platform/upstream/libnl2.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-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  */
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 -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
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 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
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
146 static void cbq_class_free_data(struct rtnl_class *class)
147 {
148         free(class->c_subdata);
149 }
150
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
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
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
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
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
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
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
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
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
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
286 static void __init cbq_init(void)
287 {
288         rtnl_qdisc_register(&cbq_qdisc_ops);
289         rtnl_class_register(&cbq_class_ops);
290 }
291
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 /** @} */