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