summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/network/networkd-network.c2
-rw-r--r--src/network/tc/drr.c2
-rw-r--r--src/network/tc/htb.c6
-rw-r--r--src/network/tc/qfq.c4
-rw-r--r--src/network/tc/tclass.c101
-rw-r--r--src/network/tc/tclass.h7
6 files changed, 84 insertions, 38 deletions
diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c
index fafa0e570e..a5bb6dd529 100644
--- a/src/network/networkd-network.c
+++ b/src/network/networkd-network.c
@@ -802,7 +802,7 @@ static Network *network_free(Network *network) {
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(network->qdiscs_by_section);
- hashmap_free_with_destructor(network->tclasses_by_section, tclass_free);
+ hashmap_free(network->tclasses_by_section);
return mfree(network);
}
diff --git a/src/network/tc/drr.c b/src/network/tc/drr.c
index 373911bc70..5d754101de 100644
--- a/src/network/tc/drr.c
+++ b/src/network/tc/drr.c
@@ -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;
diff --git a/src/network/tc/htb.c b/src/network/tc/htb.c
index 8f1faa1dc5..39f436a804 100644
--- a/src/network/tc/htb.c
+++ b/src/network/tc/htb.c
@@ -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;
diff --git a/src/network/tc/qfq.c b/src/network/tc/qfq.c
index 7702e6ff6e..0da53a89e4 100644
--- a/src/network/tc/qfq.c
+++ b/src/network/tc/qfq.c
@@ -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;
diff --git a/src/network/tc/tclass.c b/src/network/tc/tclass.c
index fcbe8cbcf4..168d93e1c5 100644
--- a/src/network/tc/tclass.c
+++ b/src/network/tc/tclass.c
@@ -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,13 @@ static int tclass_get(Link *link, const TClass *in, TClass **ret) {
return 0;
}
-static int tclass_add(Link *link, TClass *tclass) {
+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 +223,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 +240,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;
@@ -286,7 +329,7 @@ void link_tclass_drop_marked(Link *link) {
if (tclass->state == 0) {
log_tclass_debug(tclass, link, "Forgetting");
- tclass_free(tclass);
+ tclass_detach(tclass);
} else
log_tclass_debug(tclass, link, "Removed");
}
@@ -393,17 +436,17 @@ int link_request_tclass(Link *link, TClass *tclass) {
assert(tclass);
if (tclass_get(link, tclass, &existing) < 0) {
- _cleanup_(tclass_freep) TClass *tmp = NULL;
+ _cleanup_(tclass_unrefp) TClass *tmp = NULL;
r = tclass_dup(tclass, &tmp);
if (r < 0)
return log_oom();
- r = tclass_add(link, tmp);
+ r = tclass_attach(link, tmp);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to store TClass: %m");
- existing = TAKE_PTR(tmp);
+ existing = tmp;
} else
existing->source = tclass->source;
@@ -426,7 +469,7 @@ int link_request_tclass(Link *link, TClass *tclass) {
}
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;
TClass *tclass = NULL;
Link *link;
uint16_t type;
@@ -501,13 +544,13 @@ int manager_rtnl_process_tclass(sd_netlink *rtnl, sd_netlink_message *message, M
tclass_enter_configured(tmp);
log_tclass_debug(tmp, link, "Received new");
- r = tclass_add(link, tmp);
+ r = tclass_attach(link, tmp);
if (r < 0) {
log_link_warning_errno(link, r, "Failed to remember TClass, ignoring: %m");
return 0;
}
- tclass = TAKE_PTR(tmp);
+ tclass = tmp;
}
break;
@@ -566,7 +609,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 +624,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 +670,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;
diff --git a/src/network/tc/tclass.h b/src/network/tc/tclass.h
index 85df57d42c..44f7181450 100644
--- a/src/network/tc/tclass.h
+++ b/src/network/tc/tclass.h
@@ -24,6 +24,8 @@ typedef struct TClass {
NetworkConfigSource source;
NetworkConfigState state;
+ unsigned n_ref;
+
uint32_t classid;
uint32_t parent;
@@ -55,7 +57,8 @@ 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);
@@ -71,7 +74,7 @@ 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);