diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/network/networkd-link.c | 3 | ||||
-rw-r--r-- | src/network/networkd-link.h | 3 | ||||
-rw-r--r-- | src/network/networkd-network.c | 9 | ||||
-rw-r--r-- | src/network/networkd-network.h | 3 | ||||
-rw-r--r-- | src/network/networkd-queue.c | 33 | ||||
-rw-r--r-- | src/network/networkd-queue.h | 9 | ||||
-rw-r--r-- | src/network/tc/ets.c | 1 | ||||
-rw-r--r-- | src/network/tc/htb.c | 1 | ||||
-rw-r--r-- | src/network/tc/qdisc.c | 118 | ||||
-rw-r--r-- | src/network/tc/qdisc.h | 23 | ||||
-rw-r--r-- | src/network/tc/tc.c | 201 | ||||
-rw-r--r-- | src/network/tc/tc.h | 44 | ||||
-rw-r--r-- | src/network/tc/tclass.c | 104 | ||||
-rw-r--r-- | src/network/tc/tclass.h | 23 |
14 files changed, 212 insertions, 363 deletions
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index e46f209e7a..48f8e40fb4 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -210,7 +210,8 @@ static Link *link_free(Link *link) { link->nexthops = set_free(link->nexthops); link->neighbors = set_free(link->neighbors); link->addresses = set_free(link->addresses); - link->traffic_control = set_free(link->traffic_control); + link->qdiscs = set_free(link->qdiscs); + link->tclasses = set_free(link->tclasses); link->dhcp_pd_prefixes = set_free(link->dhcp_pd_prefixes); diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index 645a8e7147..733ac128ef 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -113,7 +113,8 @@ typedef struct Link { Set *neighbors; Set *routes; Set *nexthops; - Set *traffic_control; + Set *qdiscs; + Set *tclasses; sd_dhcp_client *dhcp_client; sd_dhcp_lease *dhcp_lease; diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index eeededcb6c..c6dceef1e9 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -33,6 +33,7 @@ #include "networkd-sriov.h" #include "parse-util.h" #include "path-lookup.h" +#include "qdisc.h" #include "radv-internal.h" #include "set.h" #include "socket-util.h" @@ -40,7 +41,7 @@ #include "string-table.h" #include "string-util.h" #include "strv.h" -#include "tc.h" +#include "tclass.h" #include "util.h" /* Let's assume that anything above this number is a user misconfiguration. */ @@ -322,7 +323,8 @@ int network_verify(Network *network) { network_drop_invalid_prefixes(network); network_drop_invalid_route_prefixes(network); network_drop_invalid_routing_policy_rules(network); - network_drop_invalid_traffic_control(network); + network_drop_invalid_qdisc(network); + network_drop_invalid_tclass(network); r = sr_iov_drop_invalid_sections(UINT32_MAX, network->sr_iov_by_section); if (r < 0) return r; @@ -756,7 +758,8 @@ static Network *network_free(Network *network) { hashmap_free_with_destructor(network->rules_by_section, routing_policy_rule_free); hashmap_free_with_destructor(network->dhcp_static_leases_by_section, dhcp_static_lease_free); ordered_hashmap_free_with_destructor(network->sr_iov_by_section, sr_iov_free); - hashmap_free_with_destructor(network->tc_by_section, traffic_control_free); + hashmap_free_with_destructor(network->qdiscs_by_section, qdisc_free); + hashmap_free_with_destructor(network->tclasses_by_section, tclass_free); free(network->name); diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index 299d84ed8b..74d71735fb 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -335,7 +335,8 @@ struct Network { Hashmap *route_prefixes_by_section; Hashmap *rules_by_section; Hashmap *dhcp_static_leases_by_section; - Hashmap *tc_by_section; + Hashmap *qdiscs_by_section; + Hashmap *tclasses_by_section; OrderedHashmap *sr_iov_by_section; /* All kinds of DNS configuration */ diff --git a/src/network/networkd-queue.c b/src/network/networkd-queue.c index 5d06735774..5f420c08c3 100644 --- a/src/network/networkd-queue.c +++ b/src/network/networkd-queue.c @@ -16,7 +16,8 @@ #include "networkd-routing-policy-rule.h" #include "networkd-queue.h" #include "networkd-setlink.h" -#include "tc.h" +#include "qdisc.h" +#include "tclass.h" static void request_free_object(RequestType type, void *object) { switch (type) { @@ -63,8 +64,11 @@ static void request_free_object(RequestType type, void *object) { break; case REQUEST_TYPE_SET_LINK: break; - case REQUEST_TYPE_TRAFFIC_CONTROL: - traffic_control_free(object); + case REQUEST_TYPE_TC_QDISC: + qdisc_free(object); + break; + case REQUEST_TYPE_TC_CLASS: + tclass_free(object); break; case REQUEST_TYPE_UP_DOWN: break; @@ -154,8 +158,11 @@ 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); + case REQUEST_TYPE_TC_QDISC: + qdisc_hash_func(req->qdisc, state); + break; + case REQUEST_TYPE_TC_CLASS: + tclass_hash_func(req->tclass, state); break; case REQUEST_TYPE_UP_DOWN: break; @@ -215,8 +222,10 @@ 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_TC_QDISC: + return qdisc_compare_func(a->qdisc, b->qdisc); + case REQUEST_TYPE_TC_CLASS: + return tclass_compare_func(a->tclass, b->tclass); case REQUEST_TYPE_UP_DOWN: return 0; default: @@ -305,7 +314,8 @@ int link_queue_request( REQUEST_TYPE_DHCP6_CLIENT, REQUEST_TYPE_NDISC, REQUEST_TYPE_RADV, - REQUEST_TYPE_TRAFFIC_CONTROL) || + REQUEST_TYPE_TC_QDISC, + REQUEST_TYPE_TC_CLASS) || netlink_handler); req = new(Request, 1); @@ -414,8 +424,11 @@ int manager_process_requests(sd_event_source *s, void *userdata) { case REQUEST_TYPE_SET_LINK: r = request_process_set_link(req); break; - case REQUEST_TYPE_TRAFFIC_CONTROL: - r = request_process_traffic_control(req); + case REQUEST_TYPE_TC_QDISC: + r = request_process_qdisc(req); + break; + case REQUEST_TYPE_TC_CLASS: + r = request_process_tclass(req); break; case REQUEST_TYPE_UP_DOWN: r = request_process_link_up_or_down(req); diff --git a/src/network/networkd-queue.h b/src/network/networkd-queue.h index 9b2c6baf44..593f3dde6e 100644 --- a/src/network/networkd-queue.h +++ b/src/network/networkd-queue.h @@ -14,7 +14,8 @@ typedef struct NetDev NetDev; typedef struct NextHop NextHop; typedef struct Route Route; typedef struct RoutingPolicyRule RoutingPolicyRule; -typedef struct TrafficControl TrafficControl; +typedef struct QDisc QDisc; +typedef struct TClass TClass; typedef enum RequestType { REQUEST_TYPE_ACTIVATE_LINK, @@ -35,7 +36,8 @@ typedef enum RequestType { REQUEST_TYPE_ROUTE, REQUEST_TYPE_ROUTING_POLICY_RULE, REQUEST_TYPE_SET_LINK, - REQUEST_TYPE_TRAFFIC_CONTROL, + REQUEST_TYPE_TC_CLASS, + REQUEST_TYPE_TC_QDISC, REQUEST_TYPE_UP_DOWN, _REQUEST_TYPE_MAX, _REQUEST_TYPE_INVALID = -EINVAL, @@ -57,7 +59,8 @@ typedef struct Request { RoutingPolicyRule *rule; void *set_link_operation_ptr; NetDev *netdev; - TrafficControl *traffic_control; + QDisc *qdisc; + TClass *tclass; void *object; }; void *userdata; diff --git a/src/network/tc/ets.c b/src/network/tc/ets.c index c4d594cd1b..00c46f24a4 100644 --- a/src/network/tc/ets.c +++ b/src/network/tc/ets.c @@ -5,6 +5,7 @@ #include "alloc-util.h" #include "conf-parser.h" #include "ets.h" +#include "extract-word.h" #include "memory-util.h" #include "netlink-util.h" #include "parse-util.h" diff --git a/src/network/tc/htb.c b/src/network/tc/htb.c index 78fcd3f05f..f50b0e5010 100644 --- a/src/network/tc/htb.c +++ b/src/network/tc/htb.c @@ -5,6 +5,7 @@ #include "alloc-util.h" #include "conf-parser.h" #include "netlink-util.h" +#include "networkd-link.h" #include "parse-util.h" #include "qdisc.h" #include "htb.h" diff --git a/src/network/tc/qdisc.c b/src/network/tc/qdisc.c index 665b2a270c..d69d8b48e9 100644 --- a/src/network/tc/qdisc.c +++ b/src/network/tc/qdisc.c @@ -7,7 +7,9 @@ #include "conf-parser.h" #include "in-addr-util.h" #include "netlink-util.h" +#include "networkd-link.h" #include "networkd-manager.h" +#include "networkd-network.h" #include "networkd-queue.h" #include "parse-util.h" #include "qdisc.h" @@ -50,7 +52,6 @@ static int qdisc_new(QDiscKind kind, QDisc **ret) { return -ENOMEM; *qdisc = (QDisc) { - .meta.kind = TC_KIND_QDISC, .parent = TC_H_ROOT, .kind = kind, }; @@ -60,7 +61,6 @@ static int qdisc_new(QDiscKind kind, QDisc **ret) { if (!qdisc) return -ENOMEM; - qdisc->meta.kind = TC_KIND_QDISC, qdisc->parent = TC_H_ROOT; qdisc->kind = kind; @@ -79,8 +79,7 @@ static int qdisc_new(QDiscKind kind, QDisc **ret) { int qdisc_new_static(QDiscKind kind, Network *network, const char *filename, unsigned section_line, QDisc **ret) { _cleanup_(config_section_freep) ConfigSection *n = NULL; _cleanup_(qdisc_freep) QDisc *qdisc = NULL; - TrafficControl *existing; - QDisc *q = NULL; + QDisc *existing; int r; assert(network); @@ -92,20 +91,15 @@ int qdisc_new_static(QDiscKind kind, Network *network, const char *filename, uns if (r < 0) return r; - existing = hashmap_get(network->tc_by_section, n); + existing = hashmap_get(network->qdiscs_by_section, n); if (existing) { - if (existing->kind != TC_KIND_QDISC) - return -EINVAL; - - q = TC_TO_QDISC(existing); - - if (q->kind != _QDISC_KIND_INVALID && + if (existing->kind != _QDISC_KIND_INVALID && kind != _QDISC_KIND_INVALID && - q->kind != kind) + existing->kind != kind) return -EINVAL; - if (q->kind == kind || kind == _QDISC_KIND_INVALID) { - *ret = q; + if (existing->kind == kind || kind == _QDISC_KIND_INVALID) { + *ret = existing; return 0; } } @@ -114,19 +108,19 @@ int qdisc_new_static(QDiscKind kind, Network *network, const char *filename, uns if (r < 0) return r; - if (q) { - qdisc->handle = q->handle; - qdisc->parent = q->parent; - qdisc->tca_kind = TAKE_PTR(q->tca_kind); + if (existing) { + qdisc->handle = existing->handle; + qdisc->parent = existing->parent; + qdisc->tca_kind = TAKE_PTR(existing->tca_kind); - qdisc_free(q); + qdisc_free(existing); } qdisc->network = network; qdisc->section = TAKE_PTR(n); qdisc->source = NETWORK_CONFIG_SOURCE_STATIC; - r = hashmap_ensure_put(&network->tc_by_section, &config_section_hash_ops, qdisc->section, TC(qdisc)); + r = hashmap_ensure_put(&network->qdiscs_by_section, &config_section_hash_ops, qdisc->section, qdisc); if (r < 0) return r; @@ -139,12 +133,12 @@ QDisc* qdisc_free(QDisc *qdisc) { return NULL; if (qdisc->network && qdisc->section) - hashmap_remove(qdisc->network->tc_by_section, qdisc->section); + hashmap_remove(qdisc->network->qdiscs_by_section, qdisc->section); config_section_free(qdisc->section); if (qdisc->link) - set_remove(qdisc->link->traffic_control, TC(qdisc)); + set_remove(qdisc->link->qdiscs, qdisc); free(qdisc->tca_kind); return mfree(qdisc); @@ -183,19 +177,25 @@ int qdisc_compare_func(const QDisc *a, const QDisc *b) { return strcmp_ptr(qdisc_get_tca_kind(a), qdisc_get_tca_kind(b)); } +DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR( + qdisc_hash_ops, + QDisc, + qdisc_hash_func, + qdisc_compare_func, + qdisc_free); + static int qdisc_get(Link *link, const QDisc *in, QDisc **ret) { - TrafficControl *existing; - int r; + QDisc *existing; assert(link); assert(in); - r = traffic_control_get(link, TC(in), &existing); - if (r < 0) - return r; + existing = set_get(link->qdiscs, in); + if (!existing) + return -ENOENT; if (ret) - *ret = TC_TO_QDISC(existing); + *ret = existing; return 0; } @@ -205,9 +205,11 @@ static int qdisc_add(Link *link, QDisc *qdisc) { assert(link); assert(qdisc); - r = traffic_control_add(link, TC(qdisc)); + r = set_ensure_put(&link->qdiscs, &qdisc_hash_ops, qdisc); if (r < 0) return r; + if (r == 0) + return -EEXIST; qdisc->link = link; return 0; @@ -261,20 +263,13 @@ static void log_qdisc_debug(QDisc *qdisc, Link *link, const char *str) { } int link_find_qdisc(Link *link, uint32_t handle, uint32_t parent, const char *kind, QDisc **ret) { - TrafficControl *tc; + QDisc *qdisc; assert(link); handle = TC_H_MAJ(handle); - SET_FOREACH(tc, link->traffic_control) { - QDisc *qdisc; - - if (tc->kind != TC_KIND_QDISC) - continue; - - qdisc = TC_TO_QDISC(tc); - + SET_FOREACH(qdisc, link->qdiscs) { if (qdisc->handle != handle) continue; @@ -324,10 +319,11 @@ static int qdisc_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { return 1; } -int qdisc_configure(Link *link, QDisc *qdisc) { +static int qdisc_configure(QDisc *qdisc, Link *link) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; int r; + assert(qdisc); assert(link); assert(link->manager); assert(link->manager->rtnl); @@ -355,14 +351,15 @@ int qdisc_configure(Link *link, QDisc *qdisc) { return log_link_debug_errno(link, r, "Could not send netlink message: %m"); link_ref(link); - - qdisc_enter_configuring(qdisc); return 0; } -int qdisc_is_ready_to_configure(Link *link, QDisc *qdisc) { - assert(link); +static bool qdisc_is_ready_to_configure(QDisc *qdisc, Link *link) { assert(qdisc); + assert(link); + + if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED)) + return false; if (IN_SET(qdisc->parent, TC_H_ROOT, TC_H_CLSACT)) /* TC_H_CLSACT == TC_H_INGRESS */ return true; @@ -370,6 +367,26 @@ int qdisc_is_ready_to_configure(Link *link, QDisc *qdisc) { return link_find_tclass(link, qdisc->parent, NULL) >= 0; } +int request_process_qdisc(Request *req) { + QDisc *qdisc; + Link *link; + int r; + + assert(req); + assert_se(link = req->link); + assert_se(qdisc = req->qdisc); + + if (!qdisc_is_ready_to_configure(qdisc, link)) + return 0; + + r = qdisc_configure(qdisc, link); + if (r < 0) + return log_link_warning_errno(link, r, "Failed to configure QDisc: %m"); + + qdisc_enter_configuring(qdisc); + return 1; +} + int link_request_qdisc(Link *link, QDisc *qdisc) { QDisc *existing; int r; @@ -393,7 +410,7 @@ int link_request_qdisc(Link *link, QDisc *qdisc) { existing->source = qdisc->source; log_qdisc_debug(existing, link, "Requesting"); - r = link_queue_request(link, REQUEST_TYPE_TRAFFIC_CONTROL, TC(existing), false, + r = link_queue_request(link, REQUEST_TYPE_TC_QDISC, existing, false, &link->tc_messages, NULL, NULL); if (r < 0) return log_link_warning_errno(link, r, "Failed to request QDisc: %m"); @@ -511,7 +528,7 @@ int manager_rtnl_process_qdisc(sd_netlink *rtnl, sd_netlink_message *message, Ma return 1; } -int qdisc_section_verify(QDisc *qdisc, bool *has_root, bool *has_clsact) { +static int qdisc_section_verify(QDisc *qdisc, bool *has_root, bool *has_clsact) { int r; assert(qdisc); @@ -546,6 +563,17 @@ int qdisc_section_verify(QDisc *qdisc, bool *has_root, bool *has_clsact) { return 0; } +void network_drop_invalid_qdisc(Network *network) { + bool has_root = false, has_clsact = false; + QDisc *qdisc; + + assert(network); + + HASHMAP_FOREACH(qdisc, network->qdiscs_by_section) + if (qdisc_section_verify(qdisc, &has_root, &has_clsact) < 0) + qdisc_free(qdisc); +} + int config_parse_qdisc_parent( const char *unit, const char *filename, diff --git a/src/network/tc/qdisc.h b/src/network/tc/qdisc.h index 1e4b72e271..54afe97ced 100644 --- a/src/network/tc/qdisc.h +++ b/src/network/tc/qdisc.h @@ -3,10 +3,12 @@ #pragma once #include "conf-parser.h" -#include "networkd-link.h" -#include "networkd-network.h" #include "networkd-util.h" -#include "tc.h" + +typedef struct Link Link; +typedef struct Manager Manager; +typedef struct Network Network; +typedef struct Request Request; typedef enum QDiscKind { QDISC_KIND_BFIFO, @@ -35,8 +37,6 @@ typedef enum QDiscKind { } QDiscKind; typedef struct QDisc { - TrafficControl meta; - Link *link; Network *network; ConfigSection *section; @@ -72,30 +72,25 @@ extern const QDiscVTable * const qdisc_vtable[_QDISC_KIND_MAX]; return (MixedCase*) q; \ } -/* For casting the various qdisc kinds into a qdisc */ -#define QDISC(q) (&(q)->meta) - DEFINE_NETWORK_CONFIG_STATE_FUNCTIONS(QDisc, qdisc); QDisc* qdisc_free(QDisc *qdisc); int qdisc_new_static(QDiscKind kind, Network *network, const char *filename, unsigned section_line, QDisc **ret); -void qdisc_hash_func(const QDisc *qdic, struct siphash *state); +void qdisc_hash_func(const QDisc *qdisc, struct siphash *state); int qdisc_compare_func(const QDisc *a, const QDisc *b); int link_find_qdisc(Link *link, uint32_t handle, uint32_t parent, const char *kind, QDisc **qdisc); +int request_process_qdisc(Request *req); 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); + +void network_drop_invalid_qdisc(Network *network); int manager_rtnl_process_qdisc(sd_netlink *rtnl, sd_netlink_message *message, Manager *m); DEFINE_SECTION_CLEANUP_FUNCTIONS(QDisc, qdisc_free); -DEFINE_TC_CAST(QDISC, QDisc); - CONFIG_PARSER_PROTOTYPE(config_parse_qdisc_parent); CONFIG_PARSER_PROTOTYPE(config_parse_qdisc_handle); diff --git a/src/network/tc/tc.c b/src/network/tc/tc.c index 796036c071..8a1c5b3a3b 100644 --- a/src/network/tc/tc.c +++ b/src/network/tc/tc.c @@ -1,134 +1,15 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "macro.h" -#include "networkd-queue.h" +#include "networkd-link.h" +#include "networkd-network.h" #include "qdisc.h" #include "tc.h" #include "tclass.h" -void traffic_control_free(TrafficControl *tc) { - if (!tc) - return; - - switch (tc->kind) { - case TC_KIND_QDISC: - qdisc_free(TC_TO_QDISC(tc)); - break; - case TC_KIND_TCLASS: - tclass_free(TC_TO_TCLASS(tc)); - break; - default: - assert_not_reached(); - } -} - -void traffic_control_hash_func(const TrafficControl *tc, struct siphash *state) { - assert(tc); - assert(state); - - siphash24_compress(&tc->kind, sizeof(tc->kind), state); - - switch (tc->kind) { - case TC_KIND_QDISC: - qdisc_hash_func(TC_TO_QDISC_CONST(tc), state); - break; - case TC_KIND_TCLASS: - tclass_hash_func(TC_TO_TCLASS_CONST(tc), state); - break; - default: - assert_not_reached(); - } -} - -int traffic_control_compare_func(const TrafficControl *a, const TrafficControl *b) { - int r; - - assert(a); - assert(b); - - r = CMP(a->kind, b->kind); - if (r != 0) - return r; - - switch (a->kind) { - case TC_KIND_QDISC: - return qdisc_compare_func(TC_TO_QDISC_CONST(a), TC_TO_QDISC_CONST(b)); - case TC_KIND_TCLASS: - return tclass_compare_func(TC_TO_TCLASS_CONST(a), TC_TO_TCLASS_CONST(b)); - default: - assert_not_reached(); - } -} - -DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR( - traffic_control_hash_ops, - TrafficControl, - traffic_control_hash_func, - traffic_control_compare_func, - traffic_control_free); - -int traffic_control_get(Link *link, const TrafficControl *in, TrafficControl **ret) { - TrafficControl *existing; - - assert(link); - assert(in); - - existing = set_get(link->traffic_control, in); - if (!existing) - return -ENOENT; - - if (ret) - *ret = existing; - return 0; -} - -int traffic_control_add(Link *link, TrafficControl *tc) { - int r; - - assert(link); - assert(tc); - - /* This must be called only from qdisc_add() or tclass_add(). */ - - r = set_ensure_put(&link->traffic_control, &traffic_control_hash_ops, tc); - if (r < 0) - return r; - if (r == 0) - return -EEXIST; - - return 0; -} - -static int traffic_control_configure(Link *link, TrafficControl *tc) { - assert(link); - assert(tc); - - switch (tc->kind) { - case TC_KIND_QDISC: - return qdisc_configure(link, TC_TO_QDISC(tc)); - case TC_KIND_TCLASS: - return tclass_configure(link, TC_TO_TCLASS(tc)); - default: - assert_not_reached(); - } -} - -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; + TClass *tclass; + QDisc *qdisc; int r; assert(link); @@ -136,8 +17,14 @@ int link_request_traffic_control(Link *link) { link->tc_configured = false; - HASHMAP_FOREACH(tc, link->network->tc_by_section) { - r = link_request_traffic_control_one(link, tc); + HASHMAP_FOREACH(qdisc, link->network->qdiscs_by_section) { + r = link_request_qdisc(link, qdisc); + if (r < 0) + return r; + } + + HASHMAP_FOREACH(tclass, link->network->tclasses_by_section) { + r = link_request_tclass(link, tclass); if (r < 0) return r; } @@ -152,67 +39,3 @@ int link_request_traffic_control(Link *link) { 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); - - switch (tc->kind) { - case TC_KIND_QDISC: - return qdisc_section_verify(TC_TO_QDISC(tc), qdisc_has_root, qdisc_has_clsact); - case TC_KIND_TCLASS: - return tclass_section_verify(TC_TO_TCLASS(tc)); - default: - assert_not_reached(); - } -} - -void network_drop_invalid_traffic_control(Network *network) { - bool has_root = false, has_clsact = false; - TrafficControl *tc; - - assert(network); - - HASHMAP_FOREACH(tc, network->tc_by_section) - if (traffic_control_section_verify(tc, &has_root, &has_clsact) < 0) - traffic_control_free(tc); -} diff --git a/src/network/tc/tc.h b/src/network/tc/tc.h index 57458ee65e..6226578ec5 100644 --- a/src/network/tc/tc.h +++ b/src/network/tc/tc.h @@ -1,48 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once -#include "networkd-link.h" - -typedef struct Request Request; - -typedef enum TrafficControlKind { - TC_KIND_QDISC, - TC_KIND_TCLASS, - TC_KIND_FILTER, - _TC_KIND_MAX, - _TC_KIND_INVALID = -EINVAL, -} TrafficControlKind; - -typedef struct TrafficControl { - TrafficControlKind kind; -} TrafficControl; - -/* For casting a tc into the various tc kinds */ -#define DEFINE_TC_CAST(UPPERCASE, MixedCase) \ - static inline MixedCase* TC_TO_##UPPERCASE(TrafficControl *tc) { \ - if (_unlikely_(!tc || tc->kind != TC_KIND_##UPPERCASE)) \ - return NULL; \ - \ - return (MixedCase*) tc; \ - } \ - static inline const MixedCase* TC_TO_##UPPERCASE##_CONST(const TrafficControl *tc) { \ - if (_unlikely_(!tc || tc->kind != TC_KIND_##UPPERCASE)) \ - return NULL; \ - \ - return (const MixedCase*) tc; \ - } - -/* For casting the various tc kinds into a tc */ -#define TC(tc) (&(tc)->meta) - -void traffic_control_free(TrafficControl *tc); -void network_drop_invalid_traffic_control(Network *network); - -void traffic_control_hash_func(const TrafficControl *tc, struct siphash *state); -int traffic_control_compare_func(const TrafficControl *a, const TrafficControl *b); - -int traffic_control_get(Link *link, const TrafficControl *in, TrafficControl **ret); -int traffic_control_add(Link *link, TrafficControl *tc); +typedef struct Link Link; 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 676733c33f..74df5528f3 100644 --- a/src/network/tc/tclass.c +++ b/src/network/tc/tclass.c @@ -7,7 +7,9 @@ #include "conf-parser.h" #include "in-addr-util.h" #include "netlink-util.h" +#include "networkd-link.h" #include "networkd-manager.h" +#include "networkd-network.h" #include "networkd-queue.h" #include "parse-util.h" #include "set.h" @@ -32,7 +34,6 @@ static int tclass_new(TClassKind kind, TClass **ret) { return -ENOMEM; *tclass = (TClass) { - .meta.kind = TC_KIND_TCLASS, .parent = TC_H_ROOT, .kind = kind, }; @@ -42,7 +43,6 @@ static int tclass_new(TClassKind kind, TClass **ret) { if (!tclass) return -ENOMEM; - tclass->meta.kind = TC_KIND_TCLASS; tclass->parent = TC_H_ROOT; tclass->kind = kind; @@ -61,7 +61,7 @@ static int tclass_new(TClassKind kind, TClass **ret) { int tclass_new_static(TClassKind kind, Network *network, const char *filename, unsigned section_line, TClass **ret) { _cleanup_(config_section_freep) ConfigSection *n = NULL; _cleanup_(tclass_freep) TClass *tclass = NULL; - TrafficControl *existing; + TClass *existing; int r; assert(network); @@ -73,19 +73,12 @@ int tclass_new_static(TClassKind kind, Network *network, const char *filename, u if (r < 0) return r; - existing = hashmap_get(network->tc_by_section, n); + existing = hashmap_get(network->tclasses_by_section, n); if (existing) { - TClass *t; - - if (existing->kind != TC_KIND_TCLASS) - return -EINVAL; - - t = TC_TO_TCLASS(existing); - - if (t->kind != kind) + if (existing->kind != kind) return -EINVAL; - *ret = t; + *ret = existing; return 0; } @@ -97,7 +90,7 @@ int tclass_new_static(TClassKind kind, Network *network, const char *filename, u tclass->section = TAKE_PTR(n); tclass->source = NETWORK_CONFIG_SOURCE_STATIC; - r = hashmap_ensure_put(&network->tc_by_section, &config_section_hash_ops, tclass->section, tclass); + r = hashmap_ensure_put(&network->tclasses_by_section, &config_section_hash_ops, tclass->section, tclass); if (r < 0) return r; @@ -110,12 +103,12 @@ TClass* tclass_free(TClass *tclass) { return NULL; if (tclass->network && tclass->section) - hashmap_remove(tclass->network->tc_by_section, tclass->section); + hashmap_remove(tclass->network->tclasses_by_section, tclass->section); config_section_free(tclass->section); if (tclass->link) - set_remove(tclass->link->traffic_control, TC(tclass)); + set_remove(tclass->link->tclasses, tclass); free(tclass->tca_kind); return mfree(tclass); @@ -154,19 +147,25 @@ int tclass_compare_func(const TClass *a, const TClass *b) { return strcmp_ptr(tclass_get_tca_kind(a), tclass_get_tca_kind(b)); } +DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR( + tclass_hash_ops, + TClass, + tclass_hash_func, + tclass_compare_func, + tclass_free); + static int tclass_get(Link *link, const TClass *in, TClass **ret) { - TrafficControl *existing; - int r; + TClass *existing; assert(link); assert(in); - r = traffic_control_get(link, TC(in), &existing); - if (r < 0) - return r; + existing = set_get(link->tclasses, in); + if (!existing) + return -ENOENT; if (ret) - *ret = TC_TO_TCLASS(existing); + *ret = existing; return 0; } @@ -176,9 +175,11 @@ static int tclass_add(Link *link, TClass *tclass) { assert(link); assert(tclass); - r = traffic_control_add(link, TC(tclass)); + r = set_ensure_put(&link->tclasses, &tclass_hash_ops, tclass); if (r < 0) return r; + if (r == 0) + return -EEXIST; tclass->link = link; return 0; @@ -214,18 +215,11 @@ static int tclass_dup(const TClass *src, TClass **ret) { } int link_find_tclass(Link *link, uint32_t classid, TClass **ret) { - TrafficControl *tc; + TClass *tclass; assert(link); - SET_FOREACH(tc, link->traffic_control) { - TClass *tclass; - - if (tc->kind != TC_KIND_TCLASS) - continue; - - tclass = TC_TO_TCLASS(tc); - + SET_FOREACH(tclass, link->tclasses) { if (tclass->classid != classid) continue; @@ -287,10 +281,11 @@ static int tclass_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { return 1; } -int tclass_configure(Link *link, TClass *tclass) { +static int tclass_configure(TClass *tclass, Link *link) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; int r; + assert(tclass); assert(link); assert(link->manager); assert(link->manager->rtnl); @@ -318,18 +313,39 @@ int tclass_configure(Link *link, TClass *tclass) { return log_link_debug_errno(link, r, "Could not send netlink message: %m"); link_ref(link); - - tclass_enter_configuring(tclass); return 0; } -int tclass_is_ready_to_configure(Link *link, TClass *tclass) { - assert(link); +static bool tclass_is_ready_to_configure(TClass *tclass, Link *link) { assert(tclass); + assert(link); + + if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED)) + return false; return link_find_qdisc(link, tclass->classid, tclass->parent, tclass_get_tca_kind(tclass), NULL) >= 0; } +int request_process_tclass(Request *req) { + TClass *tclass; + Link *link; + int r; + + assert(req); + assert_se(link = req->link); + assert_se(tclass = req->tclass); + + if (!tclass_is_ready_to_configure(tclass, link)) + return 0; + + r = tclass_configure(tclass, link); + if (r < 0) + return log_link_warning_errno(link, r, "Failed to configure TClass: %m"); + + tclass_enter_configuring(tclass); + return 1; +} + int link_request_tclass(Link *link, TClass *tclass) { TClass *existing; int r; @@ -353,7 +369,7 @@ int link_request_tclass(Link *link, TClass *tclass) { existing->source = tclass->source; log_tclass_debug(existing, link, "Requesting"); - r = link_queue_request(link, REQUEST_TYPE_TRAFFIC_CONTROL, TC(existing), false, + r = link_queue_request(link, REQUEST_TYPE_TC_CLASS, existing, false, &link->tc_messages, NULL, NULL); if (r < 0) return log_link_warning_errno(link, r, "Failed to request TClass: %m"); @@ -471,7 +487,7 @@ int manager_rtnl_process_tclass(sd_netlink *rtnl, sd_netlink_message *message, M return 1; } -int tclass_section_verify(TClass *tclass) { +static int tclass_section_verify(TClass *tclass) { int r; assert(tclass); @@ -488,6 +504,16 @@ int tclass_section_verify(TClass *tclass) { return 0; } +void network_drop_invalid_tclass(Network *network) { + TClass *tclass; + + assert(network); + + HASHMAP_FOREACH(tclass, network->tclasses_by_section) + if (tclass_section_verify(tclass) < 0) + tclass_free(tclass); +} + int config_parse_tclass_parent( const char *unit, const char *filename, diff --git a/src/network/tc/tclass.h b/src/network/tc/tclass.h index 6b12fba1e8..c588b38abe 100644 --- a/src/network/tc/tclass.h +++ b/src/network/tc/tclass.h @@ -3,10 +3,12 @@ #pragma once #include "conf-parser.h" -#include "networkd-link.h" -#include "networkd-network.h" #include "networkd-util.h" -#include "tc.h" + +typedef struct Link Link; +typedef struct Manager Manager; +typedef struct Network Network; +typedef struct Request Request; typedef enum TClassKind { TCLASS_KIND_DRR, @@ -17,8 +19,6 @@ typedef enum TClassKind { } TClassKind; typedef struct TClass { - TrafficControl meta; - Link *link; Network *network; ConfigSection *section; @@ -54,30 +54,25 @@ extern const TClassVTable * const tclass_vtable[_TCLASS_KIND_MAX]; return (MixedCase*) t; \ } -/* For casting the various tclass kinds into a tclass */ -#define TCLASS(t) (&(t)->meta) - DEFINE_NETWORK_CONFIG_STATE_FUNCTIONS(TClass, tclass); TClass* tclass_free(TClass *tclass); int tclass_new_static(TClassKind kind, Network *network, const char *filename, unsigned section_line, TClass **ret); -void tclass_hash_func(const TClass *tclass, struct siphash *state); +void tclass_hash_func(const TClass *qdisc, struct siphash *state); int tclass_compare_func(const TClass *a, const TClass *b); int link_find_tclass(Link *link, uint32_t classid, TClass **ret); +int request_process_tclass(Request *req); 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); + +void network_drop_invalid_tclass(Network *network); int manager_rtnl_process_tclass(sd_netlink *rtnl, sd_netlink_message *message, Manager *m); DEFINE_SECTION_CLEANUP_FUNCTIONS(TClass, tclass_free); -DEFINE_TC_CAST(TCLASS, TClass); - CONFIG_PARSER_PROTOTYPE(config_parse_tclass_parent); CONFIG_PARSER_PROTOTYPE(config_parse_tclass_classid); |