1 /* SPDX-License-Identifier: LGPL-2.1+
2 * Copyright © 2019 VMware, Inc. */
4 #include <linux/pkt_sched.h>
6 #include "alloc-util.h"
7 #include "conf-parser.h"
9 #include "netlink-util.h"
10 #include "networkd-manager.h"
11 #include "parse-util.h"
16 static int network_emulator_fill_message(Link
*link
, QDisc
*qdisc
, sd_netlink_message
*req
) {
17 struct tc_netem_qopt opt
= {
30 opt
.limit
= ne
->limit
;
35 if (ne
->duplicate
> 0)
36 opt
.duplicate
= ne
->duplicate
;
38 if (ne
->delay
!= USEC_INFINITY
) {
39 r
= tc_time_to_tick(ne
->delay
, &opt
.latency
);
41 return log_link_error_errno(link
, r
, "Failed to calculate latency in TCA_OPTION: %m");
44 if (ne
->jitter
!= USEC_INFINITY
) {
45 r
= tc_time_to_tick(ne
->jitter
, &opt
.jitter
);
47 return log_link_error_errno(link
, r
, "Failed to calculate jitter in TCA_OPTION: %m");
50 r
= sd_netlink_message_append_data(req
, TCA_OPTIONS
, &opt
, sizeof(struct tc_netem_qopt
));
52 return log_link_error_errno(link
, r
, "Could not append TCA_OPTION attribute: %m");
57 int config_parse_network_emulator_delay(
62 unsigned section_line
,
69 _cleanup_(qdisc_free_or_set_invalidp
) QDisc
*qdisc
= NULL
;
70 Network
*network
= data
;
80 r
= qdisc_new_static(QDISC_KIND_NETEM
, network
, filename
, section_line
, &qdisc
);
84 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
85 "More than one kind of queueing discipline, ignoring assignment: %m");
91 if (isempty(rvalue
)) {
92 if (STR_IN_SET(lvalue
, "DelaySec", "NetworkEmulatorDelaySec"))
93 ne
->delay
= USEC_INFINITY
;
94 else if (STR_IN_SET(lvalue
, "DelayJitterSec", "NetworkEmulatorDelayJitterSec"))
95 ne
->jitter
= USEC_INFINITY
;
101 r
= parse_sec(rvalue
, &u
);
103 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
104 "Failed to parse '%s=', ignoring assignment: %s",
109 if (STR_IN_SET(lvalue
, "DelaySec", "NetworkEmulatorDelaySec"))
111 else if (STR_IN_SET(lvalue
, "DelayJitterSec", "NetworkEmulatorDelayJitterSec"))
119 int config_parse_network_emulator_rate(
121 const char *filename
,
124 unsigned section_line
,
131 _cleanup_(qdisc_free_or_set_invalidp
) QDisc
*qdisc
= NULL
;
132 Network
*network
= data
;
142 r
= qdisc_new_static(QDISC_KIND_NETEM
, network
, filename
, section_line
, &qdisc
);
146 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
147 "More than one kind of queueing discipline, ignoring assignment: %m");
153 if (isempty(rvalue
)) {
154 if (STR_IN_SET(lvalue
, "LossRate", "NetworkEmulatorLossRate"))
156 else if (STR_IN_SET(lvalue
, "DuplicateRate", "NetworkEmulatorDuplicateRate"))
163 r
= parse_tc_percent(rvalue
, &rate
);
165 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
166 "Failed to parse '%s=', ignoring assignment: %s",
171 if (STR_IN_SET(lvalue
, "LossRate", "NetworkEmulatorLossRate"))
173 else if (STR_IN_SET(lvalue
, "DuplicateRate", "NetworkEmulatorDuplicateRate"))
174 ne
->duplicate
= rate
;
180 int config_parse_network_emulator_packet_limit(
182 const char *filename
,
185 unsigned section_line
,
192 _cleanup_(qdisc_free_or_set_invalidp
) QDisc
*qdisc
= NULL
;
193 Network
*network
= data
;
202 r
= qdisc_new_static(QDISC_KIND_NETEM
, network
, filename
, section_line
, &qdisc
);
206 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
207 "More than one kind of queueing discipline, ignoring assignment: %m");
213 if (isempty(rvalue
)) {
220 r
= safe_atou(rvalue
, &ne
->limit
);
222 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
223 "Failed to parse '%s=', ignoring assignment: %s",
232 const QDiscVTable netem_vtable
= {
233 .object_size
= sizeof(NetworkEmulator
),
235 .fill_message
= network_emulator_fill_message
,