diff options
author | Yu Watanabe <watanabe.yu+github@gmail.com> | 2022-01-26 03:49:27 +0900 |
---|---|---|
committer | Yu Watanabe <watanabe.yu+github@gmail.com> | 2022-02-09 14:43:19 +0900 |
commit | 1dec9d816b752af82bcc8a567a3979314b44c93f (patch) | |
tree | 417e384f4579bf4c997b9c5fddc06362e8509f0a /src/network/tc | |
parent | b3208e0fad3e8c4c0f7d02098991e9694ff617e1 (diff) | |
download | systemd-1dec9d816b752af82bcc8a567a3979314b44c93f.tar.gz |
network: tc: use request queue to configure traffic control
But no dependency resolution is implemented.
Diffstat (limited to 'src/network/tc')
-rw-r--r-- | src/network/tc/qdisc.c | 76 | ||||
-rw-r--r-- | src/network/tc/qdisc.h | 2 | ||||
-rw-r--r-- | src/network/tc/tc.c | 76 | ||||
-rw-r--r-- | src/network/tc/tc.h | 6 | ||||
-rw-r--r-- | src/network/tc/tclass.c | 76 | ||||
-rw-r--r-- | src/network/tc/tclass.h | 2 |
6 files changed, 224 insertions, 14 deletions
diff --git a/src/network/tc/qdisc.c b/src/network/tc/qdisc.c index d1b689793c..4fa1a6f5ea 100644 --- a/src/network/tc/qdisc.c +++ b/src/network/tc/qdisc.c @@ -8,6 +8,7 @@ #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" @@ -123,6 +124,7 @@ int qdisc_new_static(QDiscKind kind, Network *network, const char *filename, uns 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) @@ -211,6 +213,35 @@ static int qdisc_add(Link *link, QDisc *qdisc) { 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; @@ -264,6 +295,8 @@ int qdisc_configure(Link *link, QDisc *qdisc) { 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) @@ -284,11 +317,52 @@ int qdisc_configure(Link *link, QDisc *qdisc) { 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; diff --git a/src/network/tc/qdisc.h b/src/network/tc/qdisc.h index 2fc1dc2b03..dc4156ad0a 100644 --- a/src/network/tc/qdisc.h +++ b/src/network/tc/qdisc.h @@ -83,6 +83,8 @@ int qdisc_new_static(QDiscKind kind, Network *network, const char *filename, uns 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); diff --git a/src/network/tc/tc.c b/src/network/tc/tc.c index 55d1b0c937..cca5a92e62 100644 --- a/src/network/tc/tc.c +++ b/src/network/tc/tc.c @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "macro.h" +#include "networkd-queue.h" #include "qdisc.h" #include "tc.h" #include "tclass.h" @@ -112,34 +113,87 @@ static int traffic_control_configure(Link *link, TrafficControl *tc) { } } -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); diff --git a/src/network/tc/tc.h b/src/network/tc/tc.h index 954dcd39f9..57458ee65e 100644 --- a/src/network/tc/tc.h +++ b/src/network/tc/tc.h @@ -3,6 +3,8 @@ #include "networkd-link.h" +typedef struct Request Request; + typedef enum TrafficControlKind { TC_KIND_QDISC, TC_KIND_TCLASS, @@ -34,7 +36,6 @@ typedef struct TrafficControl { #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); @@ -42,3 +43,6 @@ int traffic_control_compare_func(const TrafficControl *a, const TrafficControl * 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); diff --git a/src/network/tc/tclass.c b/src/network/tc/tclass.c index cd61b42c4e..2553caa76d 100644 --- a/src/network/tc/tclass.c +++ b/src/network/tc/tclass.c @@ -8,6 +8,7 @@ #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" @@ -94,6 +95,7 @@ int tclass_new_static(TClassKind kind, Network *network, const char *filename, u 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) @@ -182,6 +184,35 @@ static int tclass_add(Link *link, TClass *tclass) { 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; @@ -235,6 +266,8 @@ int tclass_configure(Link *link, TClass *tclass) { 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) @@ -255,11 +288,52 @@ int tclass_configure(Link *link, TClass *tclass) { 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; diff --git a/src/network/tc/tclass.h b/src/network/tc/tclass.h index 9e57e9566f..525630a87c 100644 --- a/src/network/tc/tclass.h +++ b/src/network/tc/tclass.h @@ -65,6 +65,8 @@ int tclass_new_static(TClassKind kind, Network *network, const char *filename, u 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); |