]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network: tc: use request queue to configure traffic control
authorYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 25 Jan 2022 18:49:27 +0000 (03:49 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 9 Feb 2022 05:43:19 +0000 (14:43 +0900)
But no dependency resolution is implemented.

src/network/networkd-link.c
src/network/networkd-queue.c
src/network/networkd-queue.h
src/network/tc/qdisc.c
src/network/tc/qdisc.h
src/network/tc/tc.c
src/network/tc/tc.h
src/network/tc/tclass.c
src/network/tc/tclass.h

index db55b467f80c15fe8c98b60cf4f883260807ffb6..43372caa3550562d148cb0a97356161f57ddce1a 100644 (file)
@@ -1097,7 +1097,7 @@ static int link_configure(Link *link) {
         if (r < 0)
                 return r;
 
-        r = link_configure_traffic_control(link);
+        r = link_request_traffic_control(link);
         if (r < 0)
                 return r;
 
index 1aa4bbae554190ab6e284cb99ff6e340f57443c6..d673c2f1550145193ae1ba7442a3a088b4a8245a 100644 (file)
@@ -16,6 +16,7 @@
 #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) {
@@ -58,6 +59,10 @@ static void request_free_object(RequestType type, void *object) {
                 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:
@@ -143,6 +148,9 @@ static void request_hash_func(const Request *req, struct siphash *state) {
         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:
@@ -196,6 +204,8 @@ static int request_compare_func(const struct Request *a, const struct Request *b
                 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:
@@ -241,7 +251,8 @@ int link_queue_request(
                       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);
@@ -347,6 +358,9 @@ int manager_process_requests(sd_event_source *s, void *userdata) {
                         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;
index ac33e885f2bc6fe29cf0eac9aeccf0b13d28e23d..ac02b9d8159b727fed0630cfd6ccbd65bf119105 100644 (file)
@@ -14,6 +14,7 @@ typedef struct NetDev NetDev;
 typedef struct NextHop NextHop;
 typedef struct Route Route;
 typedef struct RoutingPolicyRule RoutingPolicyRule;
+typedef struct TrafficControl TrafficControl;
 
 typedef enum RequestType {
         REQUEST_TYPE_ACTIVATE_LINK,
@@ -33,6 +34,7 @@ typedef enum RequestType {
         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,
@@ -54,6 +56,7 @@ typedef struct Request {
                 RoutingPolicyRule *rule;
                 void *set_link_operation_ptr;
                 NetDev *netdev;
+                TrafficControl *traffic_control;
                 void *object;
         };
         void *userdata;
index d1b689793caa8fe8e469cc58adaadcfbc5e390eb..4fa1a6f5eac89284d9f4d4ad36264ef7a632e941 100644 (file)
@@ -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;
index 2fc1dc2b039c636f762bb5cdf75eff741641c371..dc4156ad0af0674f75c87b1101598f33c74bdd6e 100644 (file)
@@ -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);
 
index 55d1b0c93713bfd719ec29de51ac16c79f0c79aa..cca5a92e6205132fff4ebc2d65e7c248407521ca 100644 (file)
@@ -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);
 
index 954dcd39f9c28a17721a8ea7cd16a179a3a39448..57458ee65e9213a82ed492c74b16a390b36e82d3 100644 (file)
@@ -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);
index cd61b42c4e241107b69b7b275ec23355913a552f..2553caa76d9cda39ca712e9d2e210db69a22c0d7 100644 (file)
@@ -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;
index 9e57e9566f8dd28323b2c057c665a404153cfa5e..525630a87cbf63e3d61985310ec6fedd36001f3a 100644 (file)
@@ -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);