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