summaryrefslogtreecommitdiff
path: root/src/network/tc
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2022-01-26 03:49:27 +0900
committerYu Watanabe <watanabe.yu+github@gmail.com>2022-02-09 14:43:19 +0900
commit1dec9d816b752af82bcc8a567a3979314b44c93f (patch)
tree417e384f4579bf4c997b9c5fddc06362e8509f0a /src/network/tc
parentb3208e0fad3e8c4c0f7d02098991e9694ff617e1 (diff)
downloadsystemd-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.c76
-rw-r--r--src/network/tc/qdisc.h2
-rw-r--r--src/network/tc/tc.c76
-rw-r--r--src/network/tc/tc.h6
-rw-r--r--src/network/tc/tclass.c76
-rw-r--r--src/network/tc/tclass.h2
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);