But no dependency resolution is implemented.
if (r < 0)
return r;
- r = link_configure_traffic_control(link);
+ r = link_request_traffic_control(link);
if (r < 0)
return r;
#include "networkd-routing-policy-rule.h"
#include "networkd-queue.h"
#include "networkd-setlink.h"
+#include "tc.h"
static void request_free_object(RequestType type, void *object) {
switch (type) {
break;
case REQUEST_TYPE_SET_LINK:
case REQUEST_TYPE_STACKED_NETDEV:
+ break;
+ case REQUEST_TYPE_TRAFFIC_CONTROL:
+ traffic_control_free(object);
+ break;
case REQUEST_TYPE_UP_DOWN:
break;
default:
case REQUEST_TYPE_SET_LINK:
trivial_hash_func(req->set_link_operation_ptr, state);
break;
+ case REQUEST_TYPE_TRAFFIC_CONTROL:
+ traffic_control_hash_func(req->traffic_control, state);
+ break;
case REQUEST_TYPE_UP_DOWN:
break;
default:
return routing_policy_rule_compare_func(a->rule, b->rule);
case REQUEST_TYPE_SET_LINK:
return trivial_compare_func(a->set_link_operation_ptr, b->set_link_operation_ptr);
+ case REQUEST_TYPE_TRAFFIC_CONTROL:
+ return traffic_control_compare_func(a->traffic_control, b->traffic_control);
case REQUEST_TYPE_UP_DOWN:
return 0;
default:
REQUEST_TYPE_DHCP4_CLIENT,
REQUEST_TYPE_DHCP6_CLIENT,
REQUEST_TYPE_NDISC,
- REQUEST_TYPE_RADV) ||
+ REQUEST_TYPE_RADV,
+ REQUEST_TYPE_TRAFFIC_CONTROL) ||
netlink_handler);
req = new(Request, 1);
case REQUEST_TYPE_STACKED_NETDEV:
r = request_process_stacked_netdev(req);
break;
+ case REQUEST_TYPE_TRAFFIC_CONTROL:
+ r = request_process_traffic_control(req);
+ break;
case REQUEST_TYPE_UP_DOWN:
r = request_process_link_up_or_down(req);
break;
typedef struct NextHop NextHop;
typedef struct Route Route;
typedef struct RoutingPolicyRule RoutingPolicyRule;
+typedef struct TrafficControl TrafficControl;
typedef enum RequestType {
REQUEST_TYPE_ACTIVATE_LINK,
REQUEST_TYPE_ROUTING_POLICY_RULE,
REQUEST_TYPE_SET_LINK,
REQUEST_TYPE_STACKED_NETDEV,
+ REQUEST_TYPE_TRAFFIC_CONTROL,
REQUEST_TYPE_UP_DOWN,
_REQUEST_TYPE_MAX,
_REQUEST_TYPE_INVALID = -EINVAL,
RoutingPolicyRule *rule;
void *set_link_operation_ptr;
NetDev *netdev;
+ TrafficControl *traffic_control;
void *object;
};
void *userdata;
#include "in-addr-util.h"
#include "netlink-util.h"
#include "networkd-manager.h"
+#include "networkd-queue.h"
#include "parse-util.h"
#include "qdisc.h"
#include "set.h"
qdisc->network = network;
qdisc->section = TAKE_PTR(n);
+ qdisc->source = NETWORK_CONFIG_SOURCE_STATIC;
r = ordered_hashmap_ensure_put(&network->tc_by_section, &config_section_hash_ops, qdisc->section, TC(qdisc));
if (r < 0)
return 0;
}
+static int qdisc_dup(const QDisc *src, QDisc **ret) {
+ _cleanup_(qdisc_freep) QDisc *dst = NULL;
+
+ assert(src);
+ assert(ret);
+
+ if (QDISC_VTABLE(src))
+ dst = memdup(src, QDISC_VTABLE(src)->object_size);
+ else
+ dst = newdup(QDisc, src, 1);
+ if (!dst)
+ return -ENOMEM;
+
+ /* clear all pointers */
+ dst->network = NULL;
+ dst->section = NULL;
+ dst->link = NULL;
+ dst->tca_kind = NULL;
+
+ if (src->tca_kind) {
+ dst->tca_kind = strdup(src->tca_kind);
+ if (!dst->tca_kind)
+ return -ENOMEM;
+ }
+
+ *ret = TAKE_PTR(dst);
+ return 0;
+}
+
static void log_qdisc_debug(QDisc *qdisc, Link *link, const char *str) {
_cleanup_free_ char *state = NULL;
assert(link->manager->rtnl);
assert(link->ifindex > 0);
+ log_qdisc_debug(qdisc, link, "Configuring");
+
r = sd_rtnl_message_new_traffic_control(link->manager->rtnl, &req, RTM_NEWQDISC,
link->ifindex, qdisc->handle, qdisc->parent);
if (r < 0)
return log_link_debug_errno(link, r, "Could not send netlink message: %m");
link_ref(link);
- link->tc_messages++;
+ qdisc_enter_configuring(qdisc);
return 0;
}
+int qdisc_is_ready_to_configure(Link *link, QDisc *qdisc) {
+ assert(link);
+ assert(qdisc);
+
+ return true;
+}
+
+int link_request_qdisc(Link *link, QDisc *qdisc) {
+ QDisc *existing;
+ int r;
+
+ assert(link);
+ assert(qdisc);
+
+ if (qdisc_get(link, qdisc, &existing) < 0) {
+ _cleanup_(qdisc_freep) QDisc *tmp = NULL;
+
+ r = qdisc_dup(qdisc, &tmp);
+ if (r < 0)
+ return log_oom();
+
+ r = qdisc_add(link, tmp);
+ if (r < 0)
+ return log_link_warning_errno(link, r, "Failed to store QDisc: %m");
+
+ existing = TAKE_PTR(tmp);
+ } else
+ existing->source = qdisc->source;
+
+ log_qdisc_debug(existing, link, "Requesting");
+ r = link_queue_request(link, REQUEST_TYPE_TRAFFIC_CONTROL, TC(existing), false,
+ &link->tc_messages, NULL, NULL);
+ if (r < 0)
+ return log_link_warning_errno(link, r, "Failed to request QDisc: %m");
+ if (r == 0)
+ return 0;
+
+ qdisc_enter_requesting(existing);
+ return 1;
+}
+
int manager_rtnl_process_qdisc(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) {
_cleanup_(qdisc_freep) QDisc *tmp = NULL;
QDisc *qdisc = NULL;
void qdisc_hash_func(const QDisc *qdic, struct siphash *state);
int qdisc_compare_func(const QDisc *a, const QDisc *b);
+int link_request_qdisc(Link *link, QDisc *qdisc);
+int qdisc_is_ready_to_configure(Link *link, QDisc *qdisc);
int qdisc_configure(Link *link, QDisc *qdisc);
int qdisc_section_verify(QDisc *qdisc, bool *has_root, bool *has_clsact);
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "macro.h"
+#include "networkd-queue.h"
#include "qdisc.h"
#include "tc.h"
#include "tclass.h"
}
}
-int link_configure_traffic_control(Link *link) {
+static int link_request_traffic_control_one(Link *link, TrafficControl *tc) {
+ assert(link);
+ assert(tc);
+
+ switch (tc->kind) {
+ case TC_KIND_QDISC:
+ return link_request_qdisc(link, TC_TO_QDISC(tc));
+ case TC_KIND_TCLASS:
+ return link_request_tclass(link, TC_TO_TCLASS(tc));
+ default:
+ assert_not_reached();
+ }
+}
+
+int link_request_traffic_control(Link *link) {
TrafficControl *tc;
int r;
assert(link);
assert(link->network);
- if (link->tc_messages != 0) {
- log_link_debug(link, "Traffic control is configuring.");
- return 0;
- }
-
link->tc_configured = false;
ORDERED_HASHMAP_FOREACH(tc, link->network->tc_by_section) {
- r = traffic_control_configure(link, tc);
+ r = link_request_traffic_control_one(link, tc);
if (r < 0)
- return log_link_error_errno(link, r, "Could not create send configuration message: %m");
+ return r;
}
- if (link->tc_messages == 0)
+ if (link->tc_messages == 0) {
link->tc_configured = true;
- else
- log_link_debug(link, "Configuring traffic control");
+ link_check_ready(link);
+ } else {
+ log_link_debug(link, "Setting traffic control");
+ link_set_state(link, LINK_STATE_CONFIGURING);
+ }
return 0;
}
+static int traffic_control_is_ready_to_configure(Link *link, TrafficControl *tc) {
+ assert(link);
+ assert(tc);
+
+ if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
+ return false;
+
+ switch(tc->kind) {
+ case TC_KIND_QDISC:
+ return qdisc_is_ready_to_configure(link, TC_TO_QDISC(tc));
+ case TC_KIND_TCLASS:
+ return tclass_is_ready_to_configure(link, TC_TO_TCLASS(tc));
+ default:
+ assert_not_reached();
+ }
+}
+
+int request_process_traffic_control(Request *req) {
+ TrafficControl *tc;
+ Link *link;
+ int r;
+
+ assert(req);
+ assert(req->traffic_control);
+ assert(req->type == REQUEST_TYPE_TRAFFIC_CONTROL);
+
+ link = ASSERT_PTR(req->link);
+ tc = ASSERT_PTR(req->traffic_control);
+
+ r = traffic_control_is_ready_to_configure(link, tc);
+ if (r <= 0) {
+ return r;
+ }
+
+ r = traffic_control_configure(link, tc);
+ if (r < 0)
+ return r;
+
+ return 1;
+}
+
static int traffic_control_section_verify(TrafficControl *tc, bool *qdisc_has_root, bool *qdisc_has_clsact) {
assert(tc);
#include "networkd-link.h"
+typedef struct Request Request;
+
typedef enum TrafficControlKind {
TC_KIND_QDISC,
TC_KIND_TCLASS,
#define TC(tc) (&(tc)->meta)
void traffic_control_free(TrafficControl *tc);
-int link_configure_traffic_control(Link *link);
void network_drop_invalid_traffic_control(Network *network);
void traffic_control_hash_func(const TrafficControl *tc, struct siphash *state);
int traffic_control_get(Link *link, const TrafficControl *in, TrafficControl **ret);
int traffic_control_add(Link *link, TrafficControl *tc);
+
+int link_request_traffic_control(Link *link);
+int request_process_traffic_control(Request *req);
#include "in-addr-util.h"
#include "netlink-util.h"
#include "networkd-manager.h"
+#include "networkd-queue.h"
#include "parse-util.h"
#include "set.h"
#include "string-util.h"
tclass->network = network;
tclass->section = TAKE_PTR(n);
+ tclass->source = NETWORK_CONFIG_SOURCE_STATIC;
r = ordered_hashmap_ensure_put(&network->tc_by_section, &config_section_hash_ops, tclass->section, tclass);
if (r < 0)
return 0;
}
+static int tclass_dup(const TClass *src, TClass **ret) {
+ _cleanup_(tclass_freep) TClass *dst = NULL;
+
+ assert(src);
+ assert(ret);
+
+ if (TCLASS_VTABLE(src))
+ dst = memdup(src, TCLASS_VTABLE(src)->object_size);
+ else
+ dst = newdup(TClass, src, 1);
+ if (!dst)
+ return -ENOMEM;
+
+ /* clear all pointers */
+ dst->network = NULL;
+ dst->section = NULL;
+ dst->link = NULL;
+ dst->tca_kind = NULL;
+
+ if (src->tca_kind) {
+ dst->tca_kind = strdup(src->tca_kind);
+ if (!dst->tca_kind)
+ return -ENOMEM;
+ }
+
+ *ret = TAKE_PTR(dst);
+ return 0;
+}
+
static void log_tclass_debug(TClass *tclass, Link *link, const char *str) {
_cleanup_free_ char *state = NULL;
assert(link->manager->rtnl);
assert(link->ifindex > 0);
+ log_tclass_debug(tclass, link, "Configuring");
+
r = sd_rtnl_message_new_traffic_control(link->manager->rtnl, &req, RTM_NEWTCLASS,
link->ifindex, tclass->classid, tclass->parent);
if (r < 0)
return log_link_debug_errno(link, r, "Could not send netlink message: %m");
link_ref(link);
- link->tc_messages++;
+ tclass_enter_configuring(tclass);
return 0;
}
+int tclass_is_ready_to_configure(Link *link, TClass *tclass) {
+ assert(link);
+ assert(tclass);
+
+ return true;
+}
+
+int link_request_tclass(Link *link, TClass *tclass) {
+ TClass *existing;
+ int r;
+
+ assert(link);
+ assert(tclass);
+
+ if (tclass_get(link, tclass, &existing) < 0) {
+ _cleanup_(tclass_freep) TClass *tmp = NULL;
+
+ r = tclass_dup(tclass, &tmp);
+ if (r < 0)
+ return log_oom();
+
+ r = tclass_add(link, tmp);
+ if (r < 0)
+ return log_link_warning_errno(link, r, "Failed to store TClass: %m");
+
+ existing = TAKE_PTR(tmp);
+ } else
+ existing->source = tclass->source;
+
+ log_tclass_debug(existing, link, "Requesting");
+ r = link_queue_request(link, REQUEST_TYPE_TRAFFIC_CONTROL, TC(existing), false,
+ &link->tc_messages, NULL, NULL);
+ if (r < 0)
+ return log_link_warning_errno(link, r, "Failed to request TClass: %m");
+ if (r == 0)
+ return 0;
+
+ tclass_enter_requesting(existing);
+ return 1;
+}
+
int manager_rtnl_process_tclass(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) {
_cleanup_(tclass_freep) TClass *tmp = NULL;
TClass *tclass = NULL;
void tclass_hash_func(const TClass *tclass, struct siphash *state);
int tclass_compare_func(const TClass *a, const TClass *b);
+int link_request_tclass(Link *link, TClass *tclass);
+int tclass_is_ready_to_configure(Link *link, TClass *tclass);
int tclass_configure(Link *link, TClass *tclass);
int tclass_section_verify(TClass *tclass);