mirror of
https://github.com/systemd/systemd.git
synced 2024-12-22 17:35:35 +03:00
network: traffic control: drop meta from QDisc and TClass
Since #22248, it is not necessary to manage QDisc and TClass in same Set or Hashmap. Let's manage them independently.
This commit is contained in:
parent
a23e4f60d5
commit
3a67b8bb0d
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
if (existing->kind != kind)
|
||||
return -EINVAL;
|
||||
|
||||
t = TC_TO_TCLASS(existing);
|
||||
|
||||
if (t->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,
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user