1 /*
2 * lib/route/qdisc/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-2011 Thomas Graf <tgraf@suug.ch>
10 */
11
12 #include <netlink-private/netlink.h>
13 #include <netlink-private/tc.h>
14 #include <netlink/netlink.h>
15 #include <netlink/utils.h>
16 #include <netlink-private/route/tc-api.h>
17 #include <netlink/route/qdisc.h>
18 #include <netlink/route/class.h>
19 #include <netlink/route/link.h>
20 #include <netlink/route/qdisc/cbq.h>
21 #include <netlink/route/cls/police.h>
22
23 /**
24 * @ingroup qdisc
25 * @ingroup class
26 * @defgroup qdisc_cbq Class Based Queueing (CBQ)
27 * @{
28 */
29
30 static const struct trans_tbl ovl_strategies[] = {
31 __ADD(TC_CBQ_OVL_CLASSIC,classic),
32 __ADD(TC_CBQ_OVL_DELAY,delay),
33 __ADD(TC_CBQ_OVL_LOWPRIO,lowprio),
34 __ADD(TC_CBQ_OVL_DROP,drop),
35 __ADD(TC_CBQ_OVL_RCLASSIC,rclassic),
36 };
37
38 /**
39 * Convert a CBQ OVL strategy to a character string
40 * @arg type CBQ OVL strategy
41 * @arg buf destination buffer
42 * @arg len length of destination buffer
43 *
44 * Converts a CBQ OVL strategy to a character string and stores in the
45 * provided buffer. Returns the destination buffer or the type
46 * encoded in hex if no match was found.
47 */
nl_ovl_strategy2str(int type,char * buf,size_t len)48 char *nl_ovl_strategy2str(int type, char *buf, size_t len)
49 {
50 return __type2str(type, buf, len, ovl_strategies,
51 ARRAY_SIZE(ovl_strategies));
52 }
53
54 /**
55 * Convert a string to a CBQ OVL strategy
56 * @arg name CBQ OVL stragegy name
57 *
58 * Converts a CBQ OVL stragegy name to it's corresponding CBQ OVL strategy
59 * type. Returns the type or -1 if none was found.
60 */
nl_str2ovl_strategy(const char * name)61 int nl_str2ovl_strategy(const char *name)
62 {
63 return __str2type(name, ovl_strategies, ARRAY_SIZE(ovl_strategies));
64 }
65
66 static struct nla_policy cbq_policy[TCA_CBQ_MAX+1] = {
67 [TCA_CBQ_LSSOPT] = { .minlen = sizeof(struct tc_cbq_lssopt) },
68 [TCA_CBQ_RATE] = { .minlen = sizeof(struct tc_ratespec) },
69 [TCA_CBQ_WRROPT] = { .minlen = sizeof(struct tc_cbq_wrropt) },
70 [TCA_CBQ_OVL_STRATEGY] = { .minlen = sizeof(struct tc_cbq_ovl) },
71 [TCA_CBQ_FOPT] = { .minlen = sizeof(struct tc_cbq_fopt) },
72 [TCA_CBQ_POLICE] = { .minlen = sizeof(struct tc_cbq_police) },
73 };
74
cbq_msg_parser(struct rtnl_tc * tc,void * data)75 static int cbq_msg_parser(struct rtnl_tc *tc, void *data)
76 {
77 struct nlattr *tb[TCA_CBQ_MAX + 1];
78 struct rtnl_cbq *cbq = data;
79 int err;
80
81 err = tca_parse(tb, TCA_CBQ_MAX, tc, cbq_policy);
82 if (err < 0)
83 return err;
84
85 nla_memcpy(&cbq->cbq_lss, tb[TCA_CBQ_LSSOPT], sizeof(cbq->cbq_lss));
86 nla_memcpy(&cbq->cbq_rate, tb[TCA_CBQ_RATE], sizeof(cbq->cbq_rate));
87 nla_memcpy(&cbq->cbq_wrr, tb[TCA_CBQ_WRROPT], sizeof(cbq->cbq_wrr));
88 nla_memcpy(&cbq->cbq_fopt, tb[TCA_CBQ_FOPT], sizeof(cbq->cbq_fopt));
89 nla_memcpy(&cbq->cbq_ovl, tb[TCA_CBQ_OVL_STRATEGY],
90 sizeof(cbq->cbq_ovl));
91 nla_memcpy(&cbq->cbq_police, tb[TCA_CBQ_POLICE],
92 sizeof(cbq->cbq_police));
93
94 return 0;
95 }
96
cbq_dump_line(struct rtnl_tc * tc,void * data,struct nl_dump_params * p)97 static void cbq_dump_line(struct rtnl_tc *tc, void *data,
98 struct nl_dump_params *p)
99 {
100 struct rtnl_cbq *cbq = data;
101 double r, rbit;
102 char *ru, *rubit;
103
104 if (!cbq)
105 return;
106
107 r = nl_cancel_down_bytes(cbq->cbq_rate.rate, &ru);
108 rbit = nl_cancel_down_bits(cbq->cbq_rate.rate * 8, &rubit);
109
110 nl_dump(p, " rate %.2f%s/s (%.0f%s) prio %u",
111 r, ru, rbit, rubit, cbq->cbq_wrr.priority);
112 }
113
cbq_dump_details(struct rtnl_tc * tc,void * data,struct nl_dump_params * p)114 static void cbq_dump_details(struct rtnl_tc *tc, void *data,
115 struct nl_dump_params *p)
116 {
117 struct rtnl_cbq *cbq = data;
118 char *unit, buf[32];
119 double w;
120 uint32_t el;
121
122 if (!cbq)
123 return;
124
125 w = nl_cancel_down_bits(cbq->cbq_wrr.weight * 8, &unit);
126
127 nl_dump(p, "avgpkt %u mpu %u cell %u allot %u weight %.0f%s\n",
128 cbq->cbq_lss.avpkt,
129 cbq->cbq_rate.mpu,
130 1 << cbq->cbq_rate.cell_log,
131 cbq->cbq_wrr.allot, w, unit);
132
133 el = cbq->cbq_lss.ewma_log;
134 nl_dump_line(p, " minidle %uus maxidle %uus offtime "
135 "%uus level %u ewma_log %u\n",
136 nl_ticks2us(cbq->cbq_lss.minidle >> el),
137 nl_ticks2us(cbq->cbq_lss.maxidle >> el),
138 nl_ticks2us(cbq->cbq_lss.offtime >> el),
139 cbq->cbq_lss.level,
140 cbq->cbq_lss.ewma_log);
141
142 nl_dump_line(p, " penalty %uus strategy %s ",
143 nl_ticks2us(cbq->cbq_ovl.penalty),
144 nl_ovl_strategy2str(cbq->cbq_ovl.strategy, buf, sizeof(buf)));
145
146 nl_dump(p, "split %s defmap 0x%08x ",
147 rtnl_tc_handle2str(cbq->cbq_fopt.split, buf, sizeof(buf)),
148 cbq->cbq_fopt.defmap);
149
150 nl_dump(p, "police %s",
151 nl_police2str(cbq->cbq_police.police, buf, sizeof(buf)));
152 }
153
cbq_dump_stats(struct rtnl_tc * tc,void * data,struct nl_dump_params * p)154 static void cbq_dump_stats(struct rtnl_tc *tc, void *data,
155 struct nl_dump_params *p)
156 {
157 struct tc_cbq_xstats *x;
158
159 if (!(x = tca_xstats(tc)))
160 return;
161
162 nl_dump_line(p, " borrows overact "
163 " avgidle undertime\n");
164 nl_dump_line(p, " %10u %10u %10u %10u\n",
165 x->borrows, x->overactions, x->avgidle, x->undertime);
166 }
167
168 static struct rtnl_tc_ops cbq_qdisc_ops = {
169 .to_kind = "cbq",
170 .to_type = RTNL_TC_TYPE_QDISC,
171 .to_size = sizeof(struct rtnl_cbq),
172 .to_msg_parser = cbq_msg_parser,
173 .to_dump = {
174 [NL_DUMP_LINE] = cbq_dump_line,
175 [NL_DUMP_DETAILS] = cbq_dump_details,
176 [NL_DUMP_STATS] = cbq_dump_stats,
177 },
178 };
179
180 static struct rtnl_tc_ops cbq_class_ops = {
181 .to_kind = "cbq",
182 .to_type = RTNL_TC_TYPE_CLASS,
183 .to_size = sizeof(struct rtnl_cbq),
184 .to_msg_parser = cbq_msg_parser,
185 .to_dump = {
186 [NL_DUMP_LINE] = cbq_dump_line,
187 [NL_DUMP_DETAILS] = cbq_dump_details,
188 [NL_DUMP_STATS] = cbq_dump_stats,
189 },
190 };
191
cbq_init(void)192 static void __init cbq_init(void)
193 {
194 rtnl_tc_register(&cbq_qdisc_ops);
195 rtnl_tc_register(&cbq_class_ops);
196 }
197
cbq_exit(void)198 static void __exit cbq_exit(void)
199 {
200 rtnl_tc_unregister(&cbq_qdisc_ops);
201 rtnl_tc_unregister(&cbq_class_ops);
202 }
203
204 /** @} */
205