1
0
mirror of https://github.com/systemd/systemd.git synced 2024-12-23 21:35:11 +03:00

network: tc: use request queue to configure traffic control

But no dependency resolution is implemented.
This commit is contained in:
Yu Watanabe 2022-01-26 03:49:27 +09:00
parent b3208e0fad
commit 1dec9d816b
9 changed files with 243 additions and 16 deletions

View 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;

View 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;

View 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;

View 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;

View 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);

View 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);

View 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);

View 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;

View 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);