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:
parent
b3208e0fad
commit
1dec9d816b
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user