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"
8 #include "in-addr-util.h"
9 #include "netlink-util.h"
10 #include "networkd-manager.h"
11 #include "parse-util.h"
14 #include "string-util.h"
17 static int qdisc_new(QDiscs
**ret
) {
20 qdisc
= new(QDiscs
, 1);
29 *ret
= TAKE_PTR(qdisc
);
34 int qdisc_new_static(Network
*network
, const char *filename
, unsigned section_line
, QDiscs
**ret
) {
35 _cleanup_(network_config_section_freep
) NetworkConfigSection
*n
= NULL
;
36 _cleanup_(qdisc_freep
) QDiscs
*qdisc
= NULL
;
41 assert(!!filename
== (section_line
> 0));
44 r
= network_config_section_new(filename
, section_line
, &n
);
48 qdisc
= ordered_hashmap_get(network
->qdiscs_by_section
, n
);
50 *ret
= TAKE_PTR(qdisc
);
56 r
= qdisc_new(&qdisc
);
60 qdisc
->network
= network
;
63 qdisc
->section
= TAKE_PTR(n
);
65 r
= ordered_hashmap_ensure_allocated(&network
->qdiscs_by_section
, &network_config_hash_ops
);
69 r
= ordered_hashmap_put(network
->qdiscs_by_section
, qdisc
->section
, qdisc
);
74 *ret
= TAKE_PTR(qdisc
);
79 void qdisc_free(QDiscs
*qdisc
) {
83 if (qdisc
->network
&& qdisc
->section
)
84 ordered_hashmap_remove(qdisc
->network
->qdiscs_by_section
, qdisc
->section
);
86 network_config_section_free(qdisc
->section
);
91 static int qdisc_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, Link
*link
) {
95 assert(link
->qdisc_messages
> 0);
96 link
->qdisc_messages
--;
98 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
101 r
= sd_netlink_message_get_errno(m
);
102 if (r
< 0 && r
!= -EEXIST
) {
103 log_link_error_errno(link
, r
, "Could not set QDisc: %m");
104 link_enter_failed(link
);
108 if (link
->route_messages
== 0) {
109 log_link_debug(link
, "QDiscs configured");
110 link
->qdiscs_configured
= true;
111 link_check_ready(link
);
117 int qdisc_configure(Link
*link
, QDiscs
*qdisc
) {
118 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
;
122 assert(link
->manager
);
123 assert(link
->manager
->rtnl
);
124 assert(link
->ifindex
> 0);
126 r
= sd_rtnl_message_new_qdisc(link
->manager
->rtnl
, &req
, RTM_NEWQDISC
, qdisc
->family
, link
->ifindex
);
128 return log_link_error_errno(link
, r
, "Could not create RTM_NEWQDISC message: %m");
130 r
= sd_rtnl_message_set_qdisc_parent(req
, qdisc
->parent
);
132 return log_link_error_errno(link
, r
, "Could not create tcm_parent message: %m");
134 if (qdisc
->parent
== TC_H_CLSACT
) {
135 r
= sd_rtnl_message_set_qdisc_handle(req
, TC_H_MAKE(TC_H_CLSACT
, 0));
137 return log_link_error_errno(link
, r
, "Could not set tcm_handle message: %m");
139 r
= sd_netlink_message_append_string(req
, TCA_KIND
, "clsact");
141 return log_link_error_errno(link
, r
, "Could not append TCA_KIND attribute: %m");
144 if (qdisc
->has_network_emulator
) {
145 r
= sd_netlink_message_append_string(req
, TCA_KIND
, "netem");
147 return log_link_error_errno(link
, r
, "Could not append TCA_KIND attribute: %m");
149 r
= network_emulator_fill_message(link
, qdisc
, req
);
154 r
= netlink_call_async(link
->manager
->rtnl
, NULL
, req
, qdisc_handler
, link_netlink_destroy_callback
, link
);
156 return log_link_error_errno(link
, r
, "Could not send rtnetlink message: %m");
159 link
->qdisc_messages
++;
164 int config_parse_tc_qdiscs_parent(
166 const char *filename
,
169 unsigned section_line
,
176 _cleanup_(qdisc_free_or_set_invalidp
) QDiscs
*qdisc
= NULL
;
177 Network
*network
= data
;
185 r
= qdisc_new_static(network
, filename
, section_line
, &qdisc
);
189 if (streq(rvalue
, "root"))
190 qdisc
->parent
= TC_H_ROOT
;
191 else if (streq(rvalue
, "clsact"))
192 qdisc
->parent
= TC_H_CLSACT
;
194 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
195 "Failed to parse [QueueDiscs] 'Parent=', ignoring assignment: %s",