1 /* SPDX-License-Identifier: LGPL-2.1+
2 * Copyright © 2019 VMware, Inc. */
4 #include <linux/pkt_sched.h>
7 #include "alloc-util.h"
8 #include "conf-parser.h"
10 #include "netlink-util.h"
11 #include "networkd-manager.h"
12 #include "parse-util.h"
14 #include "string-util.h"
18 static int token_buffer_filter_fill_message(Link
*link
, QDisc
*qdisc
, sd_netlink_message
*req
) {
19 uint32_t rtab
[256], ptab
[256];
20 struct tc_tbf_qopt opt
= {};
21 TokenBufferFilter
*tbf
;
30 opt
.rate
.rate
= tbf
->rate
>= (1ULL << 32) ? ~0U : tbf
->rate
;
31 opt
.peakrate
.rate
= tbf
->peak_rate
>= (1ULL << 32) ? ~0U : tbf
->peak_rate
;
34 opt
.limit
= tbf
->limit
;
38 lim
= tbf
->rate
* (double) tbf
->latency
/ USEC_PER_SEC
+ tbf
->burst
;
39 if (tbf
->peak_rate
> 0) {
40 lim2
= tbf
->peak_rate
* (double) tbf
->latency
/ USEC_PER_SEC
+ tbf
->mtu
;
46 opt
.rate
.mpu
= tbf
->mpu
;
48 r
= tc_fill_ratespec_and_table(&opt
.rate
, rtab
, tbf
->mtu
);
50 return log_link_error_errno(link
, r
, "Failed to calculate ratespec: %m");
52 r
= tc_transmit_time(opt
.rate
.rate
, tbf
->burst
, &opt
.buffer
);
54 return log_link_error_errno(link
, r
, "Failed to calculate buffer size: %m");
56 if (opt
.peakrate
.rate
> 0) {
57 opt
.peakrate
.mpu
= tbf
->mpu
;
59 r
= tc_fill_ratespec_and_table(&opt
.peakrate
, ptab
, tbf
->mtu
);
61 return log_link_error_errno(link
, r
, "Failed to calculate ratespec: %m");
63 r
= tc_transmit_time(opt
.peakrate
.rate
, tbf
->mtu
, &opt
.mtu
);
65 return log_link_error_errno(link
, r
, "Failed to calculate mtu size: %m");
68 r
= sd_netlink_message_open_container_union(req
, TCA_OPTIONS
, "tbf");
70 return log_link_error_errno(link
, r
, "Could not open container TCA_OPTIONS: %m");
72 r
= sd_netlink_message_append_data(req
, TCA_TBF_PARMS
, &opt
, sizeof(struct tc_tbf_qopt
));
74 return log_link_error_errno(link
, r
, "Could not append TCA_TBF_PARMS attribute: %m");
76 r
= sd_netlink_message_append_data(req
, TCA_TBF_BURST
, &tbf
->burst
, sizeof(tbf
->burst
));
78 return log_link_error_errno(link
, r
, "Could not append TCA_TBF_BURST attribute: %m");
80 if (tbf
->rate
>= (1ULL << 32)) {
81 r
= sd_netlink_message_append_u64(req
, TCA_TBF_RATE64
, tbf
->rate
);
83 return log_link_error_errno(link
, r
, "Could not append TCA_TBF_RATE64 attribute: %m");
86 r
= sd_netlink_message_append_data(req
, TCA_TBF_RTAB
, rtab
, sizeof(rtab
));
88 return log_link_error_errno(link
, r
, "Could not append TCA_TBF_RTAB attribute: %m");
90 if (opt
.peakrate
.rate
> 0) {
91 if (tbf
->peak_rate
>= (1ULL << 32)) {
92 r
= sd_netlink_message_append_u64(req
, TCA_TBF_PRATE64
, tbf
->peak_rate
);
94 return log_link_error_errno(link
, r
, "Could not append TCA_TBF_PRATE64 attribute: %m");
97 r
= sd_netlink_message_append_u32(req
, TCA_TBF_PBURST
, tbf
->mtu
);
99 return log_link_error_errno(link
, r
, "Could not append TCA_TBF_PBURST attribute: %m");
101 r
= sd_netlink_message_append_data(req
, TCA_TBF_PTAB
, ptab
, sizeof(ptab
));
103 return log_link_error_errno(link
, r
, "Could not append TCA_TBF_PTAB attribute: %m");
106 r
= sd_netlink_message_close_container(req
);
108 return log_link_error_errno(link
, r
, "Could not close container TCA_OPTIONS: %m");
113 int config_parse_tc_token_buffer_filter_size(
115 const char *filename
,
118 unsigned section_line
,
125 _cleanup_(qdisc_free_or_set_invalidp
) QDisc
*qdisc
= NULL
;
126 Network
*network
= data
;
127 TokenBufferFilter
*tbf
;
136 r
= qdisc_new_static(QDISC_KIND_TBF
, network
, filename
, section_line
, &qdisc
);
140 return log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
141 "More than one kind of queueing discipline, ignoring assignment: %m");
145 if (isempty(rvalue
)) {
146 if (streq(lvalue
, "TokenBufferFilterRate"))
148 else if (streq(lvalue
, "TokenBufferFilterBurst"))
150 else if (streq(lvalue
, "TokenBufferFilterLimitSize"))
152 else if (streq(lvalue
, "TokenBufferFilterMTUBytes"))
154 else if (streq(lvalue
, "TokenBufferFilterMPUBytes"))
156 else if (streq(lvalue
, "TokenBufferFilterPeakRate"))
163 r
= parse_size(rvalue
, 1000, &k
);
165 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
166 "Failed to parse '%s=', ignoring assignment: %s",
171 if (streq(lvalue
, "TokenBufferFilterRate"))
173 else if (streq(lvalue
, "TokenBufferFilterBurst"))
175 else if (streq(lvalue
, "TokenBufferFilterLimitSize"))
177 else if (streq(lvalue
, "TokenBufferFilterMPUBytes"))
179 else if (streq(lvalue
, "TokenBufferFilterMTUBytes"))
181 else if (streq(lvalue
, "TokenBufferFilterPeakRate"))
182 tbf
->peak_rate
= k
/ 8;
189 int config_parse_tc_token_buffer_filter_latency(
191 const char *filename
,
194 unsigned section_line
,
201 _cleanup_(qdisc_free_or_set_invalidp
) QDisc
*qdisc
= NULL
;
202 Network
*network
= data
;
203 TokenBufferFilter
*tbf
;
212 r
= qdisc_new_static(QDISC_KIND_TBF
, network
, filename
, section_line
, &qdisc
);
216 return log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
217 "More than one kind of queueing discipline, ignoring assignment: %m");
221 if (isempty(rvalue
)) {
228 r
= parse_sec(rvalue
, &u
);
230 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
231 "Failed to parse '%s=', ignoring assignment: %s",
243 static int token_buffer_filter_verify(QDisc
*qdisc
) {
244 TokenBufferFilter
*tbf
= TBF(qdisc
);
246 if (tbf
->limit
> 0 && tbf
->latency
> 0)
247 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
248 "%s: Specifying both TokenBufferFilterLimitSize= and TokenBufferFilterLatencySec= is not allowed. "
249 "Ignoring [TrafficControlQueueingDiscipline] section from line %u.",
250 qdisc
->section
->filename
, qdisc
->section
->line
);
252 if (tbf
->limit
== 0 && tbf
->latency
== 0)
253 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
254 "%s: Either TokenBufferFilterLimitSize= or TokenBufferFilterLatencySec= is required. "
255 "Ignoring [TrafficControlQueueingDiscipline] section from line %u.",
256 qdisc
->section
->filename
, qdisc
->section
->line
);
259 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
260 "%s: TokenBufferFilterRate= is mandatory. "
261 "Ignoring [TrafficControlQueueingDiscipline] section from line %u.",
262 qdisc
->section
->filename
, qdisc
->section
->line
);
265 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
266 "%s: TokenBufferFilterBurst= is mandatory. "
267 "Ignoring [TrafficControlQueueingDiscipline] section from line %u.",
268 qdisc
->section
->filename
, qdisc
->section
->line
);
270 if (tbf
->peak_rate
> 0 && tbf
->mtu
== 0)
271 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
272 "%s: TokenBufferFilterMTUBytes= is mandatory when TokenBufferFilterPeakRate= is specified. "
273 "Ignoring [TrafficControlQueueingDiscipline] section from line %u.",
274 qdisc
->section
->filename
, qdisc
->section
->line
);
279 const QDiscVTable tbf_vtable
= {
280 .object_size
= sizeof(TokenBufferFilter
),
282 .fill_message
= token_buffer_filter_fill_message
,
283 .verify
= token_buffer_filter_verify