]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/tc/cake.c
network: tc/cake: introduce CompensationMode= setting
[thirdparty/systemd.git] / src / network / tc / cake.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later
2 * Copyright © 2020 VMware, Inc. */
3
4 #include <linux/pkt_sched.h>
5
6 #include "alloc-util.h"
7 #include "cake.h"
8 #include "conf-parser.h"
9 #include "netlink-util.h"
10 #include "parse-util.h"
11 #include "qdisc.h"
12 #include "string-table.h"
13 #include "string-util.h"
14
15 static int cake_init(QDisc *qdisc) {
16 CommonApplicationsKeptEnhanced *c;
17
18 assert(qdisc);
19
20 c = CAKE(qdisc);
21
22 c->autorate = -1;
23 c->compensation_mode = _CAKE_COMPENSATION_MODE_INVALID;
24
25 return 0;
26 }
27
28 static int cake_fill_message(Link *link, QDisc *qdisc, sd_netlink_message *req) {
29 CommonApplicationsKeptEnhanced *c;
30 int r;
31
32 assert(link);
33 assert(qdisc);
34 assert(req);
35
36 c = CAKE(qdisc);
37
38 r = sd_netlink_message_open_container_union(req, TCA_OPTIONS, "cake");
39 if (r < 0)
40 return log_link_error_errno(link, r, "Could not open container TCA_OPTIONS: %m");
41
42 if (c->bandwidth > 0) {
43 r = sd_netlink_message_append_u64(req, TCA_CAKE_BASE_RATE64, c->bandwidth);
44 if (r < 0)
45 return log_link_error_errno(link, r, "Could not append TCA_CAKE_BASE_RATE64 attribute: %m");
46 }
47
48 if (c->autorate >= 0) {
49 r = sd_netlink_message_append_u32(req, TCA_CAKE_AUTORATE, c->autorate);
50 if (r < 0)
51 return log_link_error_errno(link, r, "Could not append TCA_CAKE_AUTORATE attribute: %m");
52 }
53
54 if (c->overhead_set) {
55 r = sd_netlink_message_append_s32(req, TCA_CAKE_OVERHEAD, c->overhead);
56 if (r < 0)
57 return log_link_error_errno(link, r, "Could not append TCA_CAKE_OVERHEAD attribute: %m");
58 }
59
60 if (c->compensation_mode >= 0) {
61 r = sd_netlink_message_append_u32(req, TCA_CAKE_ATM, c->compensation_mode);
62 if (r < 0)
63 return log_link_error_errno(link, r, "Could not append TCA_CAKE_ATM attribute: %m");
64 }
65
66 r = sd_netlink_message_close_container(req);
67 if (r < 0)
68 return log_link_error_errno(link, r, "Could not close container TCA_OPTIONS: %m");
69
70 return 0;
71 }
72
73 int config_parse_cake_bandwidth(
74 const char *unit,
75 const char *filename,
76 unsigned line,
77 const char *section,
78 unsigned section_line,
79 const char *lvalue,
80 int ltype,
81 const char *rvalue,
82 void *data,
83 void *userdata) {
84
85 _cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
86 CommonApplicationsKeptEnhanced *c;
87 Network *network = data;
88 uint64_t k;
89 int r;
90
91 assert(filename);
92 assert(lvalue);
93 assert(rvalue);
94 assert(data);
95
96 r = qdisc_new_static(QDISC_KIND_CAKE, network, filename, section_line, &qdisc);
97 if (r == -ENOMEM)
98 return log_oom();
99 if (r < 0) {
100 log_syntax(unit, LOG_WARNING, filename, line, r,
101 "More than one kind of queueing discipline, ignoring assignment: %m");
102 return 0;
103 }
104
105 c = CAKE(qdisc);
106
107 if (isempty(rvalue)) {
108 c->bandwidth = 0;
109
110 TAKE_PTR(qdisc);
111 return 0;
112 }
113
114 r = parse_size(rvalue, 1000, &k);
115 if (r < 0) {
116 log_syntax(unit, LOG_WARNING, filename, line, r,
117 "Failed to parse '%s=', ignoring assignment: %s",
118 lvalue, rvalue);
119 return 0;
120 }
121
122 c->bandwidth = k/8;
123 TAKE_PTR(qdisc);
124
125 return 0;
126 }
127
128 int config_parse_cake_overhead(
129 const char *unit,
130 const char *filename,
131 unsigned line,
132 const char *section,
133 unsigned section_line,
134 const char *lvalue,
135 int ltype,
136 const char *rvalue,
137 void *data,
138 void *userdata) {
139
140 _cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
141 CommonApplicationsKeptEnhanced *c;
142 Network *network = data;
143 int32_t v;
144 int r;
145
146 assert(filename);
147 assert(lvalue);
148 assert(rvalue);
149 assert(data);
150
151 r = qdisc_new_static(QDISC_KIND_CAKE, network, filename, section_line, &qdisc);
152 if (r == -ENOMEM)
153 return log_oom();
154 if (r < 0) {
155 log_syntax(unit, LOG_WARNING, filename, line, r,
156 "More than one kind of queueing discipline, ignoring assignment: %m");
157 return 0;
158 }
159
160 c = CAKE(qdisc);
161
162 if (isempty(rvalue)) {
163 c->overhead_set = false;
164 TAKE_PTR(qdisc);
165 return 0;
166 }
167
168 r = safe_atoi32(rvalue, &v);
169 if (r < 0) {
170 log_syntax(unit, LOG_WARNING, filename, line, r,
171 "Failed to parse '%s=', ignoring assignment: %s",
172 lvalue, rvalue);
173 return 0;
174 }
175 if (v < -64 || v > 256) {
176 log_syntax(unit, LOG_WARNING, filename, line, 0,
177 "Invalid '%s=', ignoring assignment: %s",
178 lvalue, rvalue);
179 return 0;
180 }
181
182 c->overhead = v;
183 c->overhead_set = true;
184 TAKE_PTR(qdisc);
185 return 0;
186 }
187
188 int config_parse_cake_tristate(
189 const char *unit,
190 const char *filename,
191 unsigned line,
192 const char *section,
193 unsigned section_line,
194 const char *lvalue,
195 int ltype,
196 const char *rvalue,
197 void *data,
198 void *userdata) {
199
200 _cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
201 CommonApplicationsKeptEnhanced *c;
202 Network *network = data;
203 int *dest, r;
204
205 assert(filename);
206 assert(lvalue);
207 assert(rvalue);
208 assert(data);
209
210 r = qdisc_new_static(QDISC_KIND_CAKE, network, filename, section_line, &qdisc);
211 if (r == -ENOMEM)
212 return log_oom();
213 if (r < 0) {
214 log_syntax(unit, LOG_WARNING, filename, line, r,
215 "More than one kind of queueing discipline, ignoring assignment: %m");
216 return 0;
217 }
218
219 c = CAKE(qdisc);
220
221 if (streq(lvalue, "AutoRateIngress"))
222 dest = &c->autorate;
223 else
224 assert_not_reached();
225
226 if (isempty(rvalue)) {
227 *dest = -1;
228 TAKE_PTR(qdisc);
229 return 0;
230 }
231
232 r = parse_boolean(rvalue);
233 if (r < 0) {
234 log_syntax(unit, LOG_WARNING, filename, line, r,
235 "Failed to parse '%s=', ignoring assignment: %s",
236 lvalue, rvalue);
237 return 0;
238 }
239
240 *dest = r;
241 TAKE_PTR(qdisc);
242 return 0;
243 }
244
245 static const char * const cake_compensation_mode_table[_CAKE_COMPENSATION_MODE_MAX] = {
246 [CAKE_COMPENSATION_MODE_NONE] = "none",
247 [CAKE_COMPENSATION_MODE_ATM] = "atm",
248 [CAKE_COMPENSATION_MODE_PTM] = "ptm",
249 };
250
251 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(cake_compensation_mode, CakeCompensationMode);
252
253 int config_parse_cake_compensation_mode(
254 const char *unit,
255 const char *filename,
256 unsigned line,
257 const char *section,
258 unsigned section_line,
259 const char *lvalue,
260 int ltype,
261 const char *rvalue,
262 void *data,
263 void *userdata) {
264
265 _cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
266 CommonApplicationsKeptEnhanced *c;
267 Network *network = data;
268 CakeCompensationMode mode;
269 int r;
270
271 assert(filename);
272 assert(lvalue);
273 assert(rvalue);
274 assert(data);
275
276 r = qdisc_new_static(QDISC_KIND_CAKE, network, filename, section_line, &qdisc);
277 if (r == -ENOMEM)
278 return log_oom();
279 if (r < 0) {
280 log_syntax(unit, LOG_WARNING, filename, line, r,
281 "More than one kind of queueing discipline, ignoring assignment: %m");
282 return 0;
283 }
284
285 c = CAKE(qdisc);
286
287 if (isempty(rvalue)) {
288 c->compensation_mode = _CAKE_COMPENSATION_MODE_INVALID;
289 TAKE_PTR(qdisc);
290 return 0;
291 }
292
293 mode = cake_compensation_mode_from_string(rvalue);
294 if (mode < 0) {
295 log_syntax(unit, LOG_WARNING, filename, line, mode,
296 "Failed to parse '%s=', ignoring assignment: %s",
297 lvalue, rvalue);
298 return 0;
299 }
300
301 c->compensation_mode = mode;
302 TAKE_PTR(qdisc);
303 return 0;
304 }
305
306 const QDiscVTable cake_vtable = {
307 .object_size = sizeof(CommonApplicationsKeptEnhanced),
308 .tca_kind = "cake",
309 .init = cake_init,
310 .fill_message = cake_fill_message,
311 };