1 /* SPDX-License-Identifier: LGPL-2.1-or-later
2 * Copyright © 2019 VMware, Inc. */
3
4 #include <linux/pkt_sched.h>
5
6 #include "alloc-util.h"
7 #include "conf-parser.h"
8 #include "netlink-util.h"
9 #include "parse-util.h"
10 #include "qdisc.h"
11 #include "string-util.h"
12
controlled_delay_init(QDisc * qdisc)13 static int controlled_delay_init(QDisc *qdisc) {
14 ControlledDelay *cd;
15
16 assert(qdisc);
17
18 cd = CODEL(qdisc);
19
20 cd->ce_threshold_usec = USEC_INFINITY;
21 cd->ecn = -1;
22
23 return 0;
24 }
25
controlled_delay_fill_message(Link * link,QDisc * qdisc,sd_netlink_message * req)26 static int controlled_delay_fill_message(Link *link, QDisc *qdisc, sd_netlink_message *req) {
27 ControlledDelay *cd;
28 int r;
29
30 assert(link);
31 assert(qdisc);
32 assert(req);
33
34 assert_se(cd = CODEL(qdisc));
35
36 r = sd_netlink_message_open_container_union(req, TCA_OPTIONS, "codel");
37 if (r < 0)
38 return r;
39
40 if (cd->packet_limit > 0) {
41 r = sd_netlink_message_append_u32(req, TCA_CODEL_LIMIT, cd->packet_limit);
42 if (r < 0)
43 return r;
44 }
45
46 if (cd->interval_usec > 0) {
47 r = sd_netlink_message_append_u32(req, TCA_CODEL_INTERVAL, cd->interval_usec);
48 if (r < 0)
49 return r;
50 }
51
52 if (cd->target_usec > 0) {
53 r = sd_netlink_message_append_u32(req, TCA_CODEL_TARGET, cd->target_usec);
54 if (r < 0)
55 return r;
56 }
57
58 if (cd->ecn >= 0) {
59 r = sd_netlink_message_append_u32(req, TCA_CODEL_ECN, cd->ecn);
60 if (r < 0)
61 return r;
62 }
63
64 if (cd->ce_threshold_usec != USEC_INFINITY) {
65 r = sd_netlink_message_append_u32(req, TCA_CODEL_CE_THRESHOLD, cd->ce_threshold_usec);
66 if (r < 0)
67 return r;
68 }
69
70 r = sd_netlink_message_close_container(req);
71 if (r < 0)
72 return r;
73
74 return 0;
75 }
76
config_parse_controlled_delay_u32(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)77 int config_parse_controlled_delay_u32(
78 const char *unit,
79 const char *filename,
80 unsigned line,
81 const char *section,
82 unsigned section_line,
83 const char *lvalue,
84 int ltype,
85 const char *rvalue,
86 void *data,
87 void *userdata) {
88
89 _cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
90 ControlledDelay *cd;
91 Network *network = data;
92 int r;
93
94 assert(filename);
95 assert(lvalue);
96 assert(rvalue);
97 assert(data);
98
99 r = qdisc_new_static(QDISC_KIND_CODEL, network, filename, section_line, &qdisc);
100 if (r == -ENOMEM)
101 return log_oom();
102 if (r < 0) {
103 log_syntax(unit, LOG_WARNING, filename, line, r,
104 "More than one kind of queueing discipline, ignoring assignment: %m");
105 return 0;
106 }
107
108 cd = CODEL(qdisc);
109
110 if (isempty(rvalue)) {
111 cd->packet_limit = 0;
112
113 qdisc = NULL;
114 return 0;
115 }
116
117 r = safe_atou32(rvalue, &cd->packet_limit);
118 if (r < 0) {
119 log_syntax(unit, LOG_WARNING, filename, line, r,
120 "Failed to parse '%s=', ignoring assignment: %s",
121 lvalue, rvalue);
122 return 0;
123 }
124
125 qdisc = NULL;
126
127 return 0;
128 }
129
config_parse_controlled_delay_usec(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)130 int config_parse_controlled_delay_usec(
131 const char *unit,
132 const char *filename,
133 unsigned line,
134 const char *section,
135 unsigned section_line,
136 const char *lvalue,
137 int ltype,
138 const char *rvalue,
139 void *data,
140 void *userdata) {
141
142 _cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
143 ControlledDelay *cd;
144 Network *network = data;
145 usec_t *p;
146 int r;
147
148 assert(filename);
149 assert(lvalue);
150 assert(rvalue);
151 assert(data);
152
153 r = qdisc_new_static(QDISC_KIND_CODEL, network, filename, section_line, &qdisc);
154 if (r == -ENOMEM)
155 return log_oom();
156 if (r < 0) {
157 log_syntax(unit, LOG_WARNING, filename, line, r,
158 "More than one kind of queueing discipline, ignoring assignment: %m");
159 return 0;
160 }
161
162 cd = CODEL(qdisc);
163
164 if (streq(lvalue, "TargetSec"))
165 p = &cd->target_usec;
166 else if (streq(lvalue, "IntervalSec"))
167 p = &cd->interval_usec;
168 else if (streq(lvalue, "CEThresholdSec"))
169 p = &cd->ce_threshold_usec;
170 else
171 assert_not_reached();
172
173 if (isempty(rvalue)) {
174 if (streq(lvalue, "CEThresholdSec"))
175 *p = USEC_INFINITY;
176 else
177 *p = 0;
178
179 qdisc = NULL;
180 return 0;
181 }
182
183 r = parse_sec(rvalue, p);
184 if (r < 0) {
185 log_syntax(unit, LOG_WARNING, filename, line, r,
186 "Failed to parse '%s=', ignoring assignment: %s",
187 lvalue, rvalue);
188 return 0;
189 }
190
191 qdisc = NULL;
192
193 return 0;
194 }
195
config_parse_controlled_delay_bool(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)196 int config_parse_controlled_delay_bool(
197 const char *unit,
198 const char *filename,
199 unsigned line,
200 const char *section,
201 unsigned section_line,
202 const char *lvalue,
203 int ltype,
204 const char *rvalue,
205 void *data,
206 void *userdata) {
207
208 _cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
209 ControlledDelay *cd;
210 Network *network = data;
211 int r;
212
213 assert(filename);
214 assert(lvalue);
215 assert(rvalue);
216 assert(data);
217
218 r = qdisc_new_static(QDISC_KIND_CODEL, network, filename, section_line, &qdisc);
219 if (r == -ENOMEM)
220 return log_oom();
221 if (r < 0) {
222 log_syntax(unit, LOG_WARNING, filename, line, r,
223 "More than one kind of queueing discipline, ignoring assignment: %m");
224 return 0;
225 }
226
227 cd = CODEL(qdisc);
228
229 if (isempty(rvalue)) {
230 cd->ecn = -1;
231
232 qdisc = NULL;
233 return 0;
234 }
235
236 r = parse_boolean(rvalue);
237 if (r < 0) {
238 log_syntax(unit, LOG_WARNING, filename, line, r,
239 "Failed to parse '%s=', ignoring assignment: %s",
240 lvalue, rvalue);
241 return 0;
242 }
243
244 cd->ecn = r;
245 qdisc = NULL;
246
247 return 0;
248 }
249
250 const QDiscVTable codel_vtable = {
251 .object_size = sizeof(ControlledDelay),
252 .tca_kind = "codel",
253 .init = controlled_delay_init,
254 .fill_message = controlled_delay_fill_message,
255 };
256