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

Merge pull request #34224 from yuwata/network-make-qdisc-reconfigurable

network: make qdisc reconfigurable
This commit is contained in:
Daan De Meyer 2024-09-04 12:07:16 +02:00 committed by GitHub
commit 5064de1383
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
27 changed files with 394 additions and 219 deletions

View File

@ -892,7 +892,7 @@ int sd_rtnl_message_new_addrlabel(
return r;
if (nlmsg_type == RTM_NEWADDRLABEL)
(*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
(*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE;
addrlabel = NLMSG_DATA((*ret)->hdr);
@ -1143,7 +1143,7 @@ int sd_rtnl_message_new_traffic_control(
return r;
if (IN_SET(nlmsg_type, RTM_NEWQDISC, RTM_NEWTCLASS))
(*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
(*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE;
tcm = NLMSG_DATA((*ret)->hdr);
tcm->tcm_ifindex = ifindex;
@ -1212,7 +1212,7 @@ int sd_rtnl_message_new_mdb(
return r;
if (nlmsg_type == RTM_NEWMDB)
(*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
(*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE;
bpm = NLMSG_DATA((*ret)->hdr);
bpm->family = AF_BRIDGE;

View File

@ -343,6 +343,9 @@ static int link_request_neighbor(Link *link, const Neighbor *neighbor) {
return 0;
}
if (neighbor_get_request(link, neighbor, NULL) >= 0)
return 0; /* already requested, skipping. */
r = neighbor_dup(neighbor, &tmp);
if (r < 0)
return r;

View File

@ -801,8 +801,8 @@ static Network *network_free(Network *network) {
hashmap_free(network->rules_by_section);
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->qdiscs_by_section, qdisc_free);
hashmap_free_with_destructor(network->tclasses_by_section, tclass_free);
hashmap_free(network->qdiscs_by_section);
hashmap_free(network->tclasses_by_section);
return mfree(network);
}

View File

@ -150,7 +150,7 @@ int config_parse_cake_bandwidth(
void *data,
void *userdata) {
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
_cleanup_(qdisc_unref_or_set_invalidp) QDisc *qdisc = NULL;
CommonApplicationsKeptEnhanced *c;
Network *network = ASSERT_PTR(data);
uint64_t k;
@ -204,7 +204,7 @@ int config_parse_cake_overhead(
void *data,
void *userdata) {
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
_cleanup_(qdisc_unref_or_set_invalidp) QDisc *qdisc = NULL;
CommonApplicationsKeptEnhanced *c;
Network *network = ASSERT_PTR(data);
int32_t v;
@ -263,7 +263,7 @@ int config_parse_cake_mpu(
void *data,
void *userdata) {
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
_cleanup_(qdisc_unref_or_set_invalidp) QDisc *qdisc = NULL;
CommonApplicationsKeptEnhanced *c;
Network *network = ASSERT_PTR(data);
uint32_t v;
@ -321,7 +321,7 @@ int config_parse_cake_tristate(
void *data,
void *userdata) {
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
_cleanup_(qdisc_unref_or_set_invalidp) QDisc *qdisc = NULL;
CommonApplicationsKeptEnhanced *c;
Network *network = ASSERT_PTR(data);
int *dest, r;
@ -386,7 +386,7 @@ int config_parse_cake_compensation_mode(
void *data,
void *userdata) {
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
_cleanup_(qdisc_unref_or_set_invalidp) QDisc *qdisc = NULL;
CommonApplicationsKeptEnhanced *c;
Network *network = ASSERT_PTR(data);
CakeCompensationMode mode;
@ -451,7 +451,7 @@ int config_parse_cake_flow_isolation_mode(
void *data,
void *userdata) {
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
_cleanup_(qdisc_unref_or_set_invalidp) QDisc *qdisc = NULL;
CommonApplicationsKeptEnhanced *c;
Network *network = ASSERT_PTR(data);
CakeFlowIsolationMode mode;
@ -513,7 +513,7 @@ int config_parse_cake_priority_queueing_preset(
void *data,
void *userdata) {
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
_cleanup_(qdisc_unref_or_set_invalidp) QDisc *qdisc = NULL;
CommonApplicationsKeptEnhanced *c;
CakePriorityQueueingPreset preset;
Network *network = ASSERT_PTR(data);
@ -565,7 +565,7 @@ int config_parse_cake_fwmark(
void *data,
void *userdata) {
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
_cleanup_(qdisc_unref_or_set_invalidp) QDisc *qdisc = NULL;
CommonApplicationsKeptEnhanced *c;
Network *network = ASSERT_PTR(data);
uint32_t fwmark;
@ -623,7 +623,7 @@ int config_parse_cake_rtt(
void *data,
void *userdata) {
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
_cleanup_(qdisc_unref_or_set_invalidp) QDisc *qdisc = NULL;
CommonApplicationsKeptEnhanced *c;
Network *network = ASSERT_PTR(data);
usec_t t;
@ -689,7 +689,7 @@ int config_parse_cake_ack_filter(
void *data,
void *userdata) {
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
_cleanup_(qdisc_unref_or_set_invalidp) QDisc *qdisc = NULL;
CommonApplicationsKeptEnhanced *c;
CakeAckFilter ack_filter;
Network *network = ASSERT_PTR(data);

View File

@ -86,7 +86,7 @@ int config_parse_controlled_delay_u32(
void *data,
void *userdata) {
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
_cleanup_(qdisc_unref_or_set_invalidp) QDisc *qdisc = NULL;
ControlledDelay *cd;
Network *network = ASSERT_PTR(data);
int r;
@ -138,7 +138,7 @@ int config_parse_controlled_delay_usec(
void *data,
void *userdata) {
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
_cleanup_(qdisc_unref_or_set_invalidp) QDisc *qdisc = NULL;
ControlledDelay *cd;
Network *network = ASSERT_PTR(data);
usec_t *p;
@ -203,7 +203,7 @@ int config_parse_controlled_delay_bool(
void *data,
void *userdata) {
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
_cleanup_(qdisc_unref_or_set_invalidp) QDisc *qdisc = NULL;
ControlledDelay *cd;
Network *network = ASSERT_PTR(data);
int r;

View File

@ -54,7 +54,7 @@ int config_parse_drr_size(
void *data,
void *userdata) {
_cleanup_(tclass_free_or_set_invalidp) TClass *tclass = NULL;
_cleanup_(tclass_unref_or_set_invalidp) TClass *tclass = NULL;
DeficitRoundRobinSchedulerClass *drr;
Network *network = ASSERT_PTR(data);
uint64_t u;

View File

@ -88,7 +88,7 @@ int config_parse_ets_u8(
void *data,
void *userdata) {
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
_cleanup_(qdisc_unref_or_set_invalidp) QDisc *qdisc = NULL;
EnhancedTransmissionSelection *ets;
Network *network = ASSERT_PTR(data);
uint8_t v, *p;
@ -154,7 +154,7 @@ int config_parse_ets_quanta(
void *data,
void *userdata) {
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
_cleanup_(qdisc_unref_or_set_invalidp) QDisc *qdisc = NULL;
EnhancedTransmissionSelection *ets;
Network *network = ASSERT_PTR(data);
int r;
@ -237,7 +237,7 @@ int config_parse_ets_prio(
void *data,
void *userdata) {
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
_cleanup_(qdisc_unref_or_set_invalidp) QDisc *qdisc = NULL;
EnhancedTransmissionSelection *ets;
Network *network = ASSERT_PTR(data);
int r;

View File

@ -52,7 +52,7 @@ int config_parse_pfifo_size(
void *data,
void *userdata) {
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
_cleanup_(qdisc_unref_or_set_invalidp) QDisc *qdisc = NULL;
Network *network = ASSERT_PTR(data);
FirstInFirstOut *fifo;
int r;
@ -112,7 +112,7 @@ int config_parse_bfifo_size(
void *data,
void *userdata) {
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
_cleanup_(qdisc_unref_or_set_invalidp) QDisc *qdisc = NULL;
Network *network = ASSERT_PTR(data);
FirstInFirstOut *fifo;
uint64_t u;

View File

@ -106,7 +106,7 @@ int config_parse_fair_queueing_controlled_delay_u32(
void *data,
void *userdata) {
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
_cleanup_(qdisc_unref_or_set_invalidp) QDisc *qdisc = NULL;
FairQueueingControlledDelay *fqcd;
Network *network = ASSERT_PTR(data);
uint32_t *p;
@ -166,7 +166,7 @@ int config_parse_fair_queueing_controlled_delay_usec(
void *data,
void *userdata) {
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
_cleanup_(qdisc_unref_or_set_invalidp) QDisc *qdisc = NULL;
FairQueueingControlledDelay *fqcd;
Network *network = ASSERT_PTR(data);
usec_t *p;
@ -231,7 +231,7 @@ int config_parse_fair_queueing_controlled_delay_bool(
void *data,
void *userdata) {
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
_cleanup_(qdisc_unref_or_set_invalidp) QDisc *qdisc = NULL;
FairQueueingControlledDelay *fqcd;
Network *network = ASSERT_PTR(data);
int r;
@ -276,7 +276,7 @@ int config_parse_fair_queueing_controlled_delay_size(
void *data,
void *userdata) {
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
_cleanup_(qdisc_unref_or_set_invalidp) QDisc *qdisc = NULL;
FairQueueingControlledDelay *fqcd;
Network *network = ASSERT_PTR(data);
uint64_t sz;

View File

@ -49,7 +49,7 @@ int config_parse_fq_pie_packet_limit(
void *data,
void *userdata) {
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
_cleanup_(qdisc_unref_or_set_invalidp) QDisc *qdisc = NULL;
FlowQueuePIE *fq_pie;
Network *network = ASSERT_PTR(data);
uint32_t val;

View File

@ -115,7 +115,7 @@ int config_parse_fair_queueing_u32(
void *data,
void *userdata) {
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
_cleanup_(qdisc_unref_or_set_invalidp) QDisc *qdisc = NULL;
FairQueueing *fq;
Network *network = ASSERT_PTR(data);
uint32_t *p;
@ -179,7 +179,7 @@ int config_parse_fair_queueing_size(
void *data,
void *userdata) {
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
_cleanup_(qdisc_unref_or_set_invalidp) QDisc *qdisc = NULL;
FairQueueing *fq;
Network *network = ASSERT_PTR(data);
uint64_t sz;
@ -247,7 +247,7 @@ int config_parse_fair_queueing_bool(
void *data,
void *userdata) {
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
_cleanup_(qdisc_unref_or_set_invalidp) QDisc *qdisc = NULL;
FairQueueing *fq;
Network *network = ASSERT_PTR(data);
int r;
@ -293,7 +293,7 @@ int config_parse_fair_queueing_usec(
void *data,
void *userdata) {
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
_cleanup_(qdisc_unref_or_set_invalidp) QDisc *qdisc = NULL;
FairQueueing *fq;
Network *network = ASSERT_PTR(data);
usec_t sec;
@ -353,7 +353,7 @@ int config_parse_fair_queueing_max_rate(
void *data,
void *userdata) {
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
_cleanup_(qdisc_unref_or_set_invalidp) QDisc *qdisc = NULL;
FairQueueing *fq;
Network *network = ASSERT_PTR(data);
uint64_t sz;

View File

@ -77,7 +77,7 @@ int config_parse_generic_random_early_detection_u32(
void *data,
void *userdata) {
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
_cleanup_(qdisc_unref_or_set_invalidp) QDisc *qdisc = NULL;
GenericRandomEarlyDetection *gred;
Network *network = ASSERT_PTR(data);
uint32_t *p;
@ -143,7 +143,7 @@ int config_parse_generic_random_early_detection_bool(
void *data,
void *userdata) {
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
_cleanup_(qdisc_unref_or_set_invalidp) QDisc *qdisc = NULL;
GenericRandomEarlyDetection *gred;
Network *network = ASSERT_PTR(data);
int r;

View File

@ -49,7 +49,7 @@ int config_parse_heavy_hitter_filter_packet_limit(
void *data,
void *userdata) {
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
_cleanup_(qdisc_unref_or_set_invalidp) QDisc *qdisc = NULL;
HeavyHitterFilter *hhf;
Network *network = ASSERT_PTR(data);
int r;

View File

@ -57,7 +57,7 @@ int config_parse_hierarchy_token_bucket_default_class(
void *data,
void *userdata) {
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
_cleanup_(qdisc_unref_or_set_invalidp) QDisc *qdisc = NULL;
HierarchyTokenBucket *htb;
Network *network = ASSERT_PTR(data);
int r;
@ -109,7 +109,7 @@ int config_parse_hierarchy_token_bucket_u32(
void *data,
void *userdata) {
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
_cleanup_(qdisc_unref_or_set_invalidp) QDisc *qdisc = NULL;
HierarchyTokenBucket *htb;
Network *network = ASSERT_PTR(data);
int r;
@ -251,7 +251,7 @@ int config_parse_hierarchy_token_bucket_class_u32(
void *data,
void *userdata) {
_cleanup_(tclass_free_or_set_invalidp) TClass *tclass = NULL;
_cleanup_(tclass_unref_or_set_invalidp) TClass *tclass = NULL;
HierarchyTokenBucketClass *htb;
Network *network = ASSERT_PTR(data);
uint32_t v;
@ -304,7 +304,7 @@ int config_parse_hierarchy_token_bucket_class_size(
void *data,
void *userdata) {
_cleanup_(tclass_free_or_set_invalidp) TClass *tclass = NULL;
_cleanup_(tclass_unref_or_set_invalidp) TClass *tclass = NULL;
HierarchyTokenBucketClass *htb;
Network *network = ASSERT_PTR(data);
uint64_t v;
@ -387,7 +387,7 @@ int config_parse_hierarchy_token_bucket_class_rate(
void *data,
void *userdata) {
_cleanup_(tclass_free_or_set_invalidp) TClass *tclass = NULL;
_cleanup_(tclass_unref_or_set_invalidp) TClass *tclass = NULL;
HierarchyTokenBucketClass *htb;
Network *network = ASSERT_PTR(data);
uint64_t *v;

View File

@ -60,7 +60,7 @@ int config_parse_network_emulator_delay(
void *data,
void *userdata) {
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
_cleanup_(qdisc_unref_or_set_invalidp) QDisc *qdisc = NULL;
Network *network = ASSERT_PTR(data);
NetworkEmulator *ne;
usec_t u;
@ -121,7 +121,7 @@ int config_parse_network_emulator_rate(
void *data,
void *userdata) {
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
_cleanup_(qdisc_unref_or_set_invalidp) QDisc *qdisc = NULL;
Network *network = ASSERT_PTR(data);
NetworkEmulator *ne;
uint32_t rate;
@ -181,7 +181,7 @@ int config_parse_network_emulator_packet_limit(
void *data,
void *userdata) {
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
_cleanup_(qdisc_unref_or_set_invalidp) QDisc *qdisc = NULL;
Network *network = ASSERT_PTR(data);
NetworkEmulator *ne;
int r;

View File

@ -49,7 +49,7 @@ int config_parse_pie_packet_limit(
void *data,
void *userdata) {
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
_cleanup_(qdisc_unref_or_set_invalidp) QDisc *qdisc = NULL;
ProportionalIntegralControllerEnhanced *pie;
Network *network = ASSERT_PTR(data);
int r;

View File

@ -42,8 +42,54 @@ const QDiscVTable * const qdisc_vtable[_QDISC_KIND_MAX] = {
[QDISC_KIND_TEQL] = &teql_vtable,
};
static QDisc* qdisc_detach_impl(QDisc *qdisc) {
assert(qdisc);
assert(!qdisc->link || !qdisc->network);
if (qdisc->network) {
assert(qdisc->section);
hashmap_remove(qdisc->network->qdiscs_by_section, qdisc->section);
qdisc->network = NULL;
return qdisc;
}
if (qdisc->link) {
set_remove(qdisc->link->qdiscs, qdisc);
qdisc->link = NULL;
return qdisc;
}
return NULL;
}
static void qdisc_detach(QDisc *qdisc) {
assert(qdisc);
qdisc_unref(qdisc_detach_impl(qdisc));
}
static void qdisc_hash_func(const QDisc *qdisc, struct siphash *state);
static int qdisc_compare_func(const QDisc *a, const QDisc *b);
DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
qdisc_hash_ops,
QDisc,
qdisc_hash_func,
qdisc_compare_func,
qdisc_detach);
DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
qdisc_section_hash_ops,
ConfigSection,
config_section_hash_func,
config_section_compare_func,
QDisc,
qdisc_detach);
static int qdisc_new(QDiscKind kind, QDisc **ret) {
_cleanup_(qdisc_freep) QDisc *qdisc = NULL;
_cleanup_(qdisc_unrefp) QDisc *qdisc = NULL;
int r;
if (kind == _QDISC_KIND_INVALID) {
@ -52,6 +98,7 @@ static int qdisc_new(QDiscKind kind, QDisc **ret) {
return -ENOMEM;
*qdisc = (QDisc) {
.n_ref = 1,
.parent = TC_H_ROOT,
.kind = kind,
};
@ -61,6 +108,7 @@ static int qdisc_new(QDiscKind kind, QDisc **ret) {
if (!qdisc)
return -ENOMEM;
qdisc->n_ref = 1;
qdisc->parent = TC_H_ROOT;
qdisc->kind = kind;
@ -78,7 +126,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;
_cleanup_(qdisc_unrefp) QDisc *qdisc = NULL;
QDisc *existing;
int r;
@ -113,14 +161,14 @@ int qdisc_new_static(QDiscKind kind, Network *network, const char *filename, uns
qdisc->parent = existing->parent;
qdisc->tca_kind = TAKE_PTR(existing->tca_kind);
qdisc_free(existing);
qdisc_detach(existing);
}
qdisc->network = network;
qdisc->section = TAKE_PTR(n);
qdisc->source = NETWORK_CONFIG_SOURCE_STATIC;
r = hashmap_ensure_put(&network->qdiscs_by_section, &config_section_hash_ops, qdisc->section, qdisc);
r = hashmap_ensure_put(&network->qdiscs_by_section, &qdisc_section_hash_ops, qdisc->section, qdisc);
if (r < 0)
return r;
@ -128,22 +176,20 @@ int qdisc_new_static(QDiscKind kind, Network *network, const char *filename, uns
return 0;
}
QDisc* qdisc_free(QDisc *qdisc) {
static QDisc* qdisc_free(QDisc *qdisc) {
if (!qdisc)
return NULL;
if (qdisc->network && qdisc->section)
hashmap_remove(qdisc->network->qdiscs_by_section, qdisc->section);
qdisc_detach_impl(qdisc);
config_section_free(qdisc->section);
if (qdisc->link)
set_remove(qdisc->link->qdiscs, qdisc);
free(qdisc->tca_kind);
return mfree(qdisc);
}
DEFINE_TRIVIAL_REF_UNREF_FUNC(QDisc, qdisc, qdisc_free);
static const char *qdisc_get_tca_kind(const QDisc *qdisc) {
assert(qdisc);
@ -177,13 +223,6 @@ static 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) {
QDisc *existing;
@ -199,11 +238,37 @@ static int qdisc_get(Link *link, const QDisc *in, QDisc **ret) {
return 0;
}
static int qdisc_add(Link *link, QDisc *qdisc) {
static int qdisc_get_request(Link *link, const QDisc *qdisc, Request **ret) {
Request *req;
assert(link);
assert(link->manager);
assert(qdisc);
req = ordered_set_get(
link->manager->request_queue,
&(Request) {
.link = link,
.type = REQUEST_TYPE_TC_QDISC,
.userdata = (void*) qdisc,
.hash_func = (hash_func_t) qdisc_hash_func,
.compare_func = (compare_func_t) qdisc_compare_func,
});
if (!req)
return -ENOENT;
if (ret)
*ret = req;
return 0;
}
static int qdisc_attach(Link *link, QDisc *qdisc) {
int r;
assert(link);
assert(qdisc);
assert(!qdisc->link);
assert(!qdisc->network);
r = set_ensure_put(&link->qdiscs, &qdisc_hash_ops, qdisc);
if (r < 0)
@ -212,11 +277,12 @@ static int qdisc_add(Link *link, QDisc *qdisc) {
return -EEXIST;
qdisc->link = link;
qdisc_ref(qdisc);
return 0;
}
static int qdisc_dup(const QDisc *src, QDisc **ret) {
_cleanup_(qdisc_freep) QDisc *dst = NULL;
_cleanup_(qdisc_unrefp) QDisc *dst = NULL;
assert(src);
assert(ret);
@ -228,7 +294,8 @@ static int qdisc_dup(const QDisc *src, QDisc **ret) {
if (!dst)
return -ENOMEM;
/* clear all pointers */
/* clear the reference counter and all pointers */
dst->n_ref = 1;
dst->network = NULL;
dst->section = NULL;
dst->link = NULL;
@ -311,21 +378,25 @@ void link_qdisc_drop_marked(Link *link) {
assert(link);
SET_FOREACH(qdisc, link->qdiscs) {
Request *req;
if (!qdisc_is_marked(qdisc))
continue;
qdisc_unmark(qdisc);
qdisc_enter_removed(qdisc);
if (qdisc_get_request(link, qdisc, &req) >= 0)
qdisc_enter_removed(req->userdata);
if (qdisc->state == 0) {
log_qdisc_debug(qdisc, link, "Forgetting");
qdisc_free(qdisc);
qdisc_detach(qdisc);
} else
log_qdisc_debug(qdisc, link, "Removed");
}
}
QDisc* qdisc_drop(QDisc *qdisc) {
static void qdisc_drop(QDisc *qdisc) {
assert(qdisc);
assert(qdisc->link);
@ -334,8 +405,6 @@ QDisc* qdisc_drop(QDisc *qdisc) {
/* link_qdisc_drop_marked() may invalidate qdisc, so run link_tclass_drop_marked() first. */
link_tclass_drop_marked(qdisc->link);
link_qdisc_drop_marked(qdisc->link);
return NULL;
}
static int qdisc_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, QDisc *qdisc) {
@ -418,6 +487,7 @@ static bool qdisc_is_ready_to_configure(QDisc *qdisc, Link *link) {
}
static int qdisc_process_request(Request *req, Link *link, QDisc *qdisc) {
QDisc *existing;
int r;
assert(req);
@ -432,51 +502,56 @@ static int qdisc_process_request(Request *req, Link *link, QDisc *qdisc) {
return log_link_warning_errno(link, r, "Failed to configure QDisc: %m");
qdisc_enter_configuring(qdisc);
if (qdisc_get(link, qdisc, &existing) >= 0)
qdisc_enter_configuring(existing);
return 1;
}
int link_request_qdisc(Link *link, QDisc *qdisc) {
QDisc *existing;
int link_request_qdisc(Link *link, const QDisc *qdisc) {
_cleanup_(qdisc_unrefp) QDisc *tmp = NULL;
QDisc *existing = NULL;
int r;
assert(link);
assert(qdisc);
assert(qdisc->source != NETWORK_CONFIG_SOURCE_FOREIGN);
if (qdisc_get(link, qdisc, &existing) < 0) {
_cleanup_(qdisc_freep) QDisc *tmp = NULL;
if (qdisc_get_request(link, qdisc, NULL) >= 0)
return 0; /* already requested, skipping. */
r = qdisc_dup(qdisc, &tmp);
if (r < 0)
return log_oom();
r = qdisc_dup(qdisc, &tmp);
if (r < 0)
return r;
r = qdisc_add(link, tmp);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to store QDisc: %m");
if (qdisc_get(link, qdisc, &existing) >= 0)
/* Copy state for logging below. */
tmp->state = existing->state;
existing = TAKE_PTR(tmp);
} else
existing->source = qdisc->source;
log_qdisc_debug(existing, link, "Requesting");
log_qdisc_debug(tmp, link, "Requesting");
r = link_queue_request_safe(link, REQUEST_TYPE_TC_QDISC,
existing, NULL,
tmp,
qdisc_unref,
qdisc_hash_func,
qdisc_compare_func,
qdisc_process_request,
&link->tc_messages,
qdisc_handler,
NULL);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to request QDisc: %m");
if (r == 0)
return 0;
if (r <= 0)
return r;
qdisc_enter_requesting(existing);
qdisc_enter_requesting(tmp);
if (existing)
qdisc_enter_requesting(existing);
TAKE_PTR(tmp);
return 1;
}
int manager_rtnl_process_qdisc(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) {
_cleanup_(qdisc_freep) QDisc *tmp = NULL;
_cleanup_(qdisc_unrefp) QDisc *tmp = NULL;
Request *req = NULL;
QDisc *qdisc = NULL;
Link *link;
uint16_t type;
@ -541,45 +616,49 @@ int manager_rtnl_process_qdisc(sd_netlink *rtnl, sd_netlink_message *message, Ma
}
(void) qdisc_get(link, tmp, &qdisc);
(void) qdisc_get_request(link, tmp, &req);
switch (type) {
case RTM_NEWQDISC:
if (qdisc) {
qdisc_enter_configured(qdisc);
log_qdisc_debug(qdisc, link, "Received remembered");
} else {
qdisc_enter_configured(tmp);
log_qdisc_debug(tmp, link, "Received new");
r = qdisc_add(link, tmp);
if (r < 0) {
log_link_warning_errno(link, r, "Failed to remember QDisc, ignoring: %m");
return 0;
}
qdisc = TAKE_PTR(tmp);
}
if (!m->enumerating) {
/* Some kind of QDisc (e.g. tbf) also create an implicit class under the qdisc, but
* the kernel may not notify about the class. Hence, we need to enumerate classes. */
r = link_enumerate_tclass(link, qdisc->handle);
if (r < 0)
log_link_warning_errno(link, r, "Failed to enumerate TClass, ignoring: %m");
}
break;
case RTM_DELQDISC:
if (type == RTM_DELQDISC) {
if (qdisc)
qdisc_drop(qdisc);
else
log_qdisc_debug(tmp, link, "Kernel removed unknown");
break;
return 0;
}
default:
assert_not_reached();
bool is_new = false;
if (!qdisc) {
/* If we did not know the qdisc, then save it. */
r = qdisc_attach(link, tmp);
if (r < 0) {
log_link_warning_errno(link, r, "Failed to remember QDisc, ignoring: %m");
return 0;
}
qdisc = tmp;
is_new = true;
}
/* Also update information that cannot be obtained through netlink notification. */
if (req && req->waiting_reply) {
QDisc *q = ASSERT_PTR(req->userdata);
qdisc->source = q->source;
}
qdisc_enter_configured(qdisc);
if (req)
qdisc_enter_configured(req->userdata);
log_qdisc_debug(qdisc, link, is_new ? "Remembering" : "Received remembered");
if (!m->enumerating) {
/* Some kind of QDisc (e.g. tbf) also create an implicit class under the qdisc, but
* the kernel may not notify about the class. Hence, we need to enumerate classes. */
r = link_enumerate_tclass(link, qdisc->handle);
if (r < 0)
log_link_warning_errno(link, r, "Failed to enumerate TClass, ignoring: %m");
}
return 1;
@ -628,7 +707,7 @@ void network_drop_invalid_qdisc(Network *network) {
HASHMAP_FOREACH(qdisc, network->qdiscs_by_section)
if (qdisc_section_verify(qdisc, &has_root, &has_clsact) < 0)
qdisc_free(qdisc);
qdisc_detach(qdisc);
}
int config_parse_qdisc_parent(
@ -643,7 +722,7 @@ int config_parse_qdisc_parent(
void *data,
void *userdata) {
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
_cleanup_(qdisc_unref_or_set_invalidp) QDisc *qdisc = NULL;
Network *network = ASSERT_PTR(data);
int r;
@ -702,7 +781,7 @@ int config_parse_qdisc_handle(
void *data,
void *userdata) {
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
_cleanup_(qdisc_unref_or_set_invalidp) QDisc *qdisc = NULL;
Network *network = ASSERT_PTR(data);
uint16_t n;
int r;

View File

@ -42,6 +42,8 @@ typedef struct QDisc {
NetworkConfigSource source;
NetworkConfigState state;
unsigned n_ref;
uint32_t handle;
uint32_t parent;
@ -74,22 +76,22 @@ extern const QDiscVTable * const qdisc_vtable[_QDISC_KIND_MAX];
DEFINE_NETWORK_CONFIG_STATE_FUNCTIONS(QDisc, qdisc);
QDisc* qdisc_free(QDisc *qdisc);
QDisc* qdisc_ref(QDisc *qdisc);
QDisc* qdisc_unref(QDisc *qdisc);
int qdisc_new_static(QDiscKind kind, Network *network, const char *filename, unsigned section_line, QDisc **ret);
void qdisc_mark_recursive(QDisc *qdisc);
QDisc* qdisc_drop(QDisc *qdisc);
void link_qdisc_drop_marked(Link *link);
int link_find_qdisc(Link *link, uint32_t handle, const char *kind, QDisc **qdisc);
int link_request_qdisc(Link *link, QDisc *qdisc);
int link_request_qdisc(Link *link, const QDisc *qdisc);
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_SECTION_CLEANUP_FUNCTIONS(QDisc, qdisc_unref);
CONFIG_PARSER_PROTOTYPE(config_parse_qdisc_parent);
CONFIG_PARSER_PROTOTYPE(config_parse_qdisc_handle);

View File

@ -62,7 +62,7 @@ int config_parse_quick_fair_queueing_weight(
void *data,
void *userdata) {
_cleanup_(tclass_free_or_set_invalidp) TClass *tclass = NULL;
_cleanup_(tclass_unref_or_set_invalidp) TClass *tclass = NULL;
QuickFairQueueingClass *qfq;
Network *network = ASSERT_PTR(data);
uint32_t v;
@ -122,7 +122,7 @@ int config_parse_quick_fair_queueing_max_packet(
void *data,
void *userdata) {
_cleanup_(tclass_free_or_set_invalidp) TClass *tclass = NULL;
_cleanup_(tclass_unref_or_set_invalidp) TClass *tclass = NULL;
QuickFairQueueingClass *qfq;
Network *network = ASSERT_PTR(data);
uint64_t v;

View File

@ -60,7 +60,7 @@ int config_parse_stochastic_fair_blue_u32(
void *data,
void *userdata) {
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
_cleanup_(qdisc_unref_or_set_invalidp) QDisc *qdisc = NULL;
StochasticFairBlue *sfb;
Network *network = ASSERT_PTR(data);
int r;

View File

@ -44,7 +44,7 @@ int config_parse_stochastic_fairness_queueing_perturb_period(
void *data,
void *userdata) {
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
_cleanup_(qdisc_unref_or_set_invalidp) QDisc *qdisc = NULL;
StochasticFairnessQueueing *sfq;
Network *network = ASSERT_PTR(data);
int r;

View File

@ -122,7 +122,7 @@ int config_parse_token_bucket_filter_size(
void *data,
void *userdata) {
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
_cleanup_(qdisc_unref_or_set_invalidp) QDisc *qdisc = NULL;
Network *network = ASSERT_PTR(data);
TokenBucketFilter *tbf;
uint64_t k;
@ -195,7 +195,7 @@ int config_parse_token_bucket_filter_rate(
void *data,
void *userdata) {
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
_cleanup_(qdisc_unref_or_set_invalidp) QDisc *qdisc = NULL;
Network *network = ASSERT_PTR(data);
TokenBucketFilter *tbf;
uint64_t k, *p;
@ -256,7 +256,7 @@ int config_parse_token_bucket_filter_latency(
void *data,
void *userdata) {
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
_cleanup_(qdisc_unref_or_set_invalidp) QDisc *qdisc = NULL;
Network *network = ASSERT_PTR(data);
TokenBucketFilter *tbf;
usec_t u;

View File

@ -20,13 +20,13 @@ int link_request_traffic_control(Link *link) {
HASHMAP_FOREACH(qdisc, link->network->qdiscs_by_section) {
r = link_request_qdisc(link, qdisc);
if (r < 0)
return r;
return log_link_warning_errno(link, r, "Failed to request QDisc: %m");
}
HASHMAP_FOREACH(tclass, link->network->tclasses_by_section) {
r = link_request_tclass(link, tclass);
if (r < 0)
return r;
return log_link_warning_errno(link, r, "Failed to request TClass: %m");
}
if (link->tc_messages == 0) {

View File

@ -24,8 +24,54 @@ const TClassVTable * const tclass_vtable[_TCLASS_KIND_MAX] = {
[TCLASS_KIND_QFQ] = &qfq_tclass_vtable,
};
static TClass* tclass_detach_impl(TClass *tclass) {
assert(tclass);
assert(!tclass->link || !tclass->network);
if (tclass->network) {
assert(tclass->section);
hashmap_remove(tclass->network->tclasses_by_section, tclass->section);
tclass->network = NULL;
return tclass;
}
if (tclass->link) {
set_remove(tclass->link->tclasses, tclass);
tclass->link = NULL;
return tclass;
}
return NULL;
}
static void tclass_detach(TClass *tclass) {
assert(tclass);
tclass_unref(tclass_detach_impl(tclass));
}
static void tclass_hash_func(const TClass *tclass, struct siphash *state);
static int tclass_compare_func(const TClass *a, const TClass *b);
DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
tclass_hash_ops,
TClass,
tclass_hash_func,
tclass_compare_func,
tclass_detach);
DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
tclass_section_hash_ops,
ConfigSection,
config_section_hash_func,
config_section_compare_func,
TClass,
tclass_detach);
static int tclass_new(TClassKind kind, TClass **ret) {
_cleanup_(tclass_freep) TClass *tclass = NULL;
_cleanup_(tclass_unrefp) TClass *tclass = NULL;
int r;
if (kind == _TCLASS_KIND_INVALID) {
@ -34,6 +80,7 @@ static int tclass_new(TClassKind kind, TClass **ret) {
return -ENOMEM;
*tclass = (TClass) {
.n_ref = 1,
.parent = TC_H_ROOT,
.kind = kind,
};
@ -43,6 +90,7 @@ static int tclass_new(TClassKind kind, TClass **ret) {
if (!tclass)
return -ENOMEM;
tclass->n_ref = 1;
tclass->parent = TC_H_ROOT;
tclass->kind = kind;
@ -60,7 +108,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;
_cleanup_(tclass_unrefp) TClass *tclass = NULL;
TClass *existing;
int r;
@ -90,7 +138,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->tclasses_by_section, &config_section_hash_ops, tclass->section, tclass);
r = hashmap_ensure_put(&network->tclasses_by_section, &tclass_section_hash_ops, tclass->section, tclass);
if (r < 0)
return r;
@ -98,22 +146,20 @@ int tclass_new_static(TClassKind kind, Network *network, const char *filename, u
return 0;
}
TClass* tclass_free(TClass *tclass) {
static TClass* tclass_free(TClass *tclass) {
if (!tclass)
return NULL;
if (tclass->network && tclass->section)
hashmap_remove(tclass->network->tclasses_by_section, tclass->section);
tclass_detach_impl(tclass);
config_section_free(tclass->section);
if (tclass->link)
set_remove(tclass->link->tclasses, tclass);
free(tclass->tca_kind);
return mfree(tclass);
}
DEFINE_TRIVIAL_REF_UNREF_FUNC(TClass, tclass, tclass_free);
static const char *tclass_get_tca_kind(const TClass *tclass) {
assert(tclass);
@ -147,13 +193,6 @@ static 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) {
TClass *existing;
@ -169,11 +208,37 @@ static int tclass_get(Link *link, const TClass *in, TClass **ret) {
return 0;
}
static int tclass_add(Link *link, TClass *tclass) {
static int tclass_get_request(Link *link, const TClass *tclass, Request **ret) {
Request *req;
assert(link);
assert(link->manager);
assert(tclass);
req = ordered_set_get(
link->manager->request_queue,
&(Request) {
.link = link,
.type = REQUEST_TYPE_TC_CLASS,
.userdata = (void*) tclass,
.hash_func = (hash_func_t) tclass_hash_func,
.compare_func = (compare_func_t) tclass_compare_func,
});
if (!req)
return -ENOENT;
if (ret)
*ret = req;
return 0;
}
static int tclass_attach(Link *link, TClass *tclass) {
int r;
assert(link);
assert(tclass);
assert(!tclass->link);
assert(!tclass->network);
r = set_ensure_put(&link->tclasses, &tclass_hash_ops, tclass);
if (r < 0)
@ -182,11 +247,12 @@ static int tclass_add(Link *link, TClass *tclass) {
return -EEXIST;
tclass->link = link;
tclass_ref(tclass);
return 0;
}
static int tclass_dup(const TClass *src, TClass **ret) {
_cleanup_(tclass_freep) TClass *dst = NULL;
_cleanup_(tclass_unrefp) TClass *dst = NULL;
assert(src);
assert(ret);
@ -198,7 +264,8 @@ static int tclass_dup(const TClass *src, TClass **ret) {
if (!dst)
return -ENOMEM;
/* clear all pointers */
/* clear the reference counter and all pointers */
dst->n_ref = 1;
dst->network = NULL;
dst->section = NULL;
dst->link = NULL;
@ -278,21 +345,25 @@ void link_tclass_drop_marked(Link *link) {
assert(link);
SET_FOREACH(tclass, link->tclasses) {
Request *req;
if (!tclass_is_marked(tclass))
continue;
tclass_unmark(tclass);
tclass_enter_removed(tclass);
if (tclass_get_request(link, tclass, &req) >= 0)
tclass_enter_removed(req->userdata);
if (tclass->state == 0) {
log_tclass_debug(tclass, link, "Forgetting");
tclass_free(tclass);
tclass_detach(tclass);
} else
log_tclass_debug(tclass, link, "Removed");
}
}
TClass* tclass_drop(TClass *tclass) {
static void tclass_drop(TClass *tclass) {
assert(tclass);
tclass_mark_recursive(tclass);
@ -300,8 +371,6 @@ TClass* tclass_drop(TClass *tclass) {
/* link_tclass_drop_marked() may invalidate tclass, so run link_qdisc_drop_marked() first. */
link_qdisc_drop_marked(tclass->link);
link_tclass_drop_marked(tclass->link);
return NULL;
}
static int tclass_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, TClass *tclass) {
@ -368,6 +437,7 @@ static bool tclass_is_ready_to_configure(TClass *tclass, Link *link) {
}
static int tclass_process_request(Request *req, Link *link, TClass *tclass) {
TClass *existing;
int r;
assert(req);
@ -382,51 +452,56 @@ static int tclass_process_request(Request *req, Link *link, TClass *tclass) {
return log_link_warning_errno(link, r, "Failed to configure TClass: %m");
tclass_enter_configuring(tclass);
if (tclass_get(link, tclass, &existing) >= 0)
tclass_enter_configuring(existing);
return 1;
}
int link_request_tclass(Link *link, TClass *tclass) {
TClass *existing;
int link_request_tclass(Link *link, const TClass *tclass) {
_cleanup_(tclass_unrefp) TClass *tmp = NULL;
TClass *existing = NULL;
int r;
assert(link);
assert(tclass);
assert(tclass->source != NETWORK_CONFIG_SOURCE_FOREIGN);
if (tclass_get(link, tclass, &existing) < 0) {
_cleanup_(tclass_freep) TClass *tmp = NULL;
if (tclass_get_request(link, tclass, NULL) >= 0)
return 0; /* already requested, skipping. */
r = tclass_dup(tclass, &tmp);
if (r < 0)
return log_oom();
r = tclass_dup(tclass, &tmp);
if (r < 0)
return r;
r = tclass_add(link, tmp);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to store TClass: %m");
if (tclass_get(link, tclass, &existing) >= 0)
/* Copy state for logging below. */
tmp->state = existing->state;
existing = TAKE_PTR(tmp);
} else
existing->source = tclass->source;
log_tclass_debug(existing, link, "Requesting");
log_tclass_debug(tmp, link, "Requesting");
r = link_queue_request_safe(link, REQUEST_TYPE_TC_CLASS,
existing, NULL,
tmp,
tclass_unref,
tclass_hash_func,
tclass_compare_func,
tclass_process_request,
&link->tc_messages,
tclass_handler,
NULL);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to request TClass: %m");
if (r == 0)
return 0;
if (r <= 0)
return r;
tclass_enter_requesting(existing);
tclass_enter_requesting(tmp);
if (existing)
tclass_enter_requesting(existing);
TAKE_PTR(tmp);
return 1;
}
int manager_rtnl_process_tclass(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) {
_cleanup_(tclass_freep) TClass *tmp = NULL;
_cleanup_(tclass_unrefp) TClass *tmp = NULL;
Request *req = NULL;
TClass *tclass = NULL;
Link *link;
uint16_t type;
@ -491,39 +566,42 @@ int manager_rtnl_process_tclass(sd_netlink *rtnl, sd_netlink_message *message, M
}
(void) tclass_get(link, tmp, &tclass);
(void) tclass_get_request(link, tmp, &req);
switch (type) {
case RTM_NEWTCLASS:
if (tclass) {
tclass_enter_configured(tclass);
log_tclass_debug(tclass, link, "Received remembered");
} else {
tclass_enter_configured(tmp);
log_tclass_debug(tmp, link, "Received new");
r = tclass_add(link, tmp);
if (r < 0) {
log_link_warning_errno(link, r, "Failed to remember TClass, ignoring: %m");
return 0;
}
tclass = TAKE_PTR(tmp);
}
break;
case RTM_DELTCLASS:
if (type == RTM_DELTCLASS) {
if (tclass)
(void) tclass_drop(tclass);
tclass_drop(tclass);
else
log_tclass_debug(tmp, link, "Kernel removed unknown");
break;
default:
assert_not_reached();
return 0;
}
bool is_new = false;
if (!tclass) {
/* If we did not know the tclass, then save it. */
r = tclass_attach(link, tmp);
if (r < 0) {
log_link_warning_errno(link, r, "Failed to remember TClass, ignoring: %m");
return 0;
}
tclass = tmp;
is_new = true;
}
/* Also update information that cannot be obtained through netlink notification. */
if (req && req->waiting_reply) {
TClass *t = ASSERT_PTR(req->userdata);
tclass->source = t->source;
}
tclass_enter_configured(tclass);
if (req)
tclass_enter_configured(req->userdata);
log_tclass_debug(tclass, link, is_new ? "Remembering" : "Received remembered");
return 1;
}
@ -566,7 +644,7 @@ void network_drop_invalid_tclass(Network *network) {
HASHMAP_FOREACH(tclass, network->tclasses_by_section)
if (tclass_section_verify(tclass) < 0)
tclass_free(tclass);
tclass_detach(tclass);
}
int config_parse_tclass_parent(
@ -581,7 +659,7 @@ int config_parse_tclass_parent(
void *data,
void *userdata) {
_cleanup_(tclass_free_or_set_invalidp) TClass *tclass = NULL;
_cleanup_(tclass_unref_or_set_invalidp) TClass *tclass = NULL;
Network *network = ASSERT_PTR(data);
int r;
@ -627,7 +705,7 @@ int config_parse_tclass_classid(
void *data,
void *userdata) {
_cleanup_(tclass_free_or_set_invalidp) TClass *tclass = NULL;
_cleanup_(tclass_unref_or_set_invalidp) TClass *tclass = NULL;
Network *network = ASSERT_PTR(data);
int r;

View File

@ -24,6 +24,8 @@ typedef struct TClass {
NetworkConfigSource source;
NetworkConfigState state;
unsigned n_ref;
uint32_t classid;
uint32_t parent;
@ -55,23 +57,23 @@ extern const TClassVTable * const tclass_vtable[_TCLASS_KIND_MAX];
DEFINE_NETWORK_CONFIG_STATE_FUNCTIONS(TClass, tclass);
TClass* tclass_free(TClass *tclass);
TClass* tclass_ref(TClass *tclass);
TClass* tclass_unref(TClass *tclass);
int tclass_new_static(TClassKind kind, Network *network, const char *filename, unsigned section_line, TClass **ret);
void tclass_mark_recursive(TClass *tclass);
TClass* tclass_drop(TClass *tclass);
void link_tclass_drop_marked(Link *link);
int link_find_tclass(Link *link, uint32_t classid, TClass **ret);
int link_request_tclass(Link *link, TClass *tclass);
int link_request_tclass(Link *link, const TClass *tclass);
void network_drop_invalid_tclass(Network *network);
int manager_rtnl_process_tclass(sd_netlink *rtnl, sd_netlink_message *message, Manager *m);
int link_enumerate_tclass(Link *link, uint32_t parent);
DEFINE_SECTION_CLEANUP_FUNCTIONS(TClass, tclass_free);
DEFINE_SECTION_CLEANUP_FUNCTIONS(TClass, tclass_unref);
CONFIG_PARSER_PROTOTYPE(config_parse_tclass_parent);
CONFIG_PARSER_PROTOTYPE(config_parse_tclass_classid);

View File

@ -50,7 +50,7 @@ int config_parse_trivial_link_equalizer_id(
void *data,
void *userdata) {
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
_cleanup_(qdisc_unref_or_set_invalidp) QDisc *qdisc = NULL;
TrivialLinkEqualizer *teql;
Network *network = ASSERT_PTR(data);
unsigned id;

View File

@ -4489,6 +4489,17 @@ class NetworkdTCTests(unittest.TestCase, Utilities):
self.assertIn('rtt 1s', output)
self.assertIn('ack-filter-aggressive', output)
# Test for replacing existing qdisc. See #31226.
with open(os.path.join(network_unit_dir, '25-qdisc-cake.network'), mode='a', encoding='utf-8') as f:
f.write('Bandwidth=250M\n')
networkctl_reload()
self.wait_online('dummy98:routable')
output = check_output('tc qdisc show dev dummy98')
print(output)
self.assertIn('bandwidth 250Mbit', output)
@expectedFailureIfModuleIsNotAvailable('sch_codel')
def test_qdisc_codel(self):
copy_network_unit('25-qdisc-codel.network', '12-dummy.netdev')