summaryrefslogtreecommitdiff
path: root/src/network/tc
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2022-01-26 13:01:19 +0900
committerYu Watanabe <watanabe.yu+github@gmail.com>2022-02-09 14:43:19 +0900
commit7ec1846242055cc68dc419ee4415b0d8b234ffd7 (patch)
treec8c78eacdc56cf961ee925bb69fbb2e6266965da /src/network/tc
parent1dec9d816b752af82bcc8a567a3979314b44c93f (diff)
downloadsystemd-7ec1846242055cc68dc419ee4415b0d8b234ffd7.tar.gz
network: tc: introduce order dependency of traffic control
Diffstat (limited to 'src/network/tc')
-rw-r--r--src/network/tc/qdisc.c43
-rw-r--r--src/network/tc/qdisc.h2
-rw-r--r--src/network/tc/tclass.c32
-rw-r--r--src/network/tc/tclass.h2
4 files changed, 77 insertions, 2 deletions
diff --git a/src/network/tc/qdisc.c b/src/network/tc/qdisc.c
index 4fa1a6f5ea..7df6449de6 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 dc4156ad0a..1e4b72e271 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 2553caa76d..903ff28336 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 525630a87c..6b12fba1e8 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);