From 7ec1846242055cc68dc419ee4415b0d8b234ffd7 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 26 Jan 2022 13:01:19 +0900 Subject: [PATCH] network: tc: introduce order dependency of traffic control --- src/network/tc/qdisc.c | 43 ++++++++++++++++++++++++++++++++++++++++- src/network/tc/qdisc.h | 2 ++ src/network/tc/tclass.c | 32 +++++++++++++++++++++++++++++- src/network/tc/tclass.h | 2 ++ 4 files changed, 77 insertions(+), 2 deletions(-) diff --git a/src/network/tc/qdisc.c b/src/network/tc/qdisc.c index 4fa1a6f5eac..7df6449de63 100644 --- a/src/network/tc/qdisc.c +++ b/src/network/tc/qdisc.c @@ -260,6 +260,44 @@ static void log_qdisc_debug(QDisc *qdisc, Link *link, const char *str) { strna(qdisc_get_tca_kind(qdisc))); } +int link_find_qdisc(Link *link, uint32_t handle, uint32_t parent, const char *kind, QDisc **ret) { + TrafficControl *tc; + + 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); + + if (qdisc->handle != handle) + continue; + + if (qdisc->parent != parent) + continue; + + if (qdisc->source == NETWORK_CONFIG_SOURCE_FOREIGN) + continue; + + if (!qdisc_exists(qdisc)) + continue; + + if (kind && !streq_ptr(kind, qdisc_get_tca_kind(qdisc))) + continue; + + if (ret) + *ret = qdisc; + return 0; + } + + return -ENOENT; +} + static int qdisc_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { int r; @@ -326,7 +364,10 @@ int qdisc_is_ready_to_configure(Link *link, QDisc *qdisc) { assert(link); assert(qdisc); - return true; + if (IN_SET(qdisc->parent, TC_H_ROOT, TC_H_CLSACT)) /* TC_H_CLSACT == TC_H_INGRESS */ + return true; + + return link_find_tclass(link, qdisc->parent, NULL) >= 0; } int link_request_qdisc(Link *link, QDisc *qdisc) { diff --git a/src/network/tc/qdisc.h b/src/network/tc/qdisc.h index dc4156ad0af..1e4b72e271f 100644 --- a/src/network/tc/qdisc.h +++ b/src/network/tc/qdisc.h @@ -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_find_qdisc(Link *link, uint32_t handle, uint32_t parent, const char *kind, QDisc **qdisc); + 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); diff --git a/src/network/tc/tclass.c b/src/network/tc/tclass.c index 2553caa76d9..903ff283362 100644 --- a/src/network/tc/tclass.c +++ b/src/network/tc/tclass.c @@ -213,6 +213,36 @@ static int tclass_dup(const TClass *src, TClass **ret) { return 0; } +int link_find_tclass(Link *link, uint32_t classid, TClass **ret) { + TrafficControl *tc; + + assert(link); + + SET_FOREACH(tc, link->traffic_control) { + TClass *tclass; + + if (tc->kind != TC_KIND_TCLASS) + continue; + + tclass = TC_TO_TCLASS(tc); + + if (tclass->classid != classid) + continue; + + if (tclass->source == NETWORK_CONFIG_SOURCE_FOREIGN) + continue; + + if (!tclass_exists(tclass)) + continue; + + if (ret) + *ret = tclass; + return 0; + } + + return -ENOENT; +} + static void log_tclass_debug(TClass *tclass, Link *link, const char *str) { _cleanup_free_ char *state = NULL; @@ -297,7 +327,7 @@ int tclass_is_ready_to_configure(Link *link, TClass *tclass) { assert(link); assert(tclass); - return true; + return link_find_qdisc(link, tclass->classid, tclass->parent, tclass_get_tca_kind(tclass), NULL) >= 0; } int link_request_tclass(Link *link, TClass *tclass) { diff --git a/src/network/tc/tclass.h b/src/network/tc/tclass.h index 525630a87cb..6b12fba1e8b 100644 --- a/src/network/tc/tclass.h +++ b/src/network/tc/tclass.h @@ -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_find_tclass(Link *link, uint32_t classid, TClass **ret); + 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);