From be8e93390003e45acbb318c6e1e48fbc3c772f78 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sat, 7 Oct 2023 14:20:38 +0900 Subject: [PATCH] network/tc: drop child tree of traffic control nodes on remove When a node of traffic control tree is removed, all child nodes are also removed but their removal are not notified by the kernel. So, previously, removed TC classes or qdiscs under the removed node were kept in the memory of networkd, and may cause failure on reconfigure. --- src/network/tc/qdisc.c | 38 ++++++++++++++++++++++++++++++-------- src/network/tc/qdisc.h | 2 ++ src/network/tc/tclass.c | 38 ++++++++++++++++++++++++++++++-------- src/network/tc/tclass.h | 2 ++ 4 files changed, 64 insertions(+), 16 deletions(-) diff --git a/src/network/tc/qdisc.c b/src/network/tc/qdisc.c index 7bb95ede75..828fe9ab82 100644 --- a/src/network/tc/qdisc.c +++ b/src/network/tc/qdisc.c @@ -293,6 +293,33 @@ int link_find_qdisc(Link *link, uint32_t handle, uint32_t parent, const char *ki return -ENOENT; } +QDisc* qdisc_drop(QDisc *qdisc) { + TClass *tclass; + Link *link; + + assert(qdisc); + + link = ASSERT_PTR(qdisc->link); + + /* also drop all child classes assigned to the qdisc. */ + SET_FOREACH(tclass, link->tclasses) { + if (TC_H_MAJ(tclass->classid) != qdisc->handle) + continue; + + tclass_drop(tclass); + } + + qdisc_enter_removed(qdisc); + + if (qdisc->state == 0) { + log_qdisc_debug(qdisc, link, "Forgetting"); + qdisc = qdisc_free(qdisc); + } else + log_qdisc_debug(qdisc, link, "Removed"); + + return qdisc; +} + static int qdisc_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, QDisc *qdisc) { int r; @@ -512,14 +539,9 @@ int manager_rtnl_process_qdisc(sd_netlink *rtnl, sd_netlink_message *message, Ma break; case RTM_DELQDISC: - if (qdisc) { - qdisc_enter_removed(qdisc); - if (qdisc->state == 0) { - log_qdisc_debug(qdisc, link, "Forgetting"); - qdisc_free(qdisc); - } else - log_qdisc_debug(qdisc, link, "Removed"); - } else + if (qdisc) + qdisc_drop(qdisc); + else log_qdisc_debug(tmp, link, "Kernel removed unknown"); break; diff --git a/src/network/tc/qdisc.h b/src/network/tc/qdisc.h index 155e2adf24..86db44763b 100644 --- a/src/network/tc/qdisc.h +++ b/src/network/tc/qdisc.h @@ -77,6 +77,8 @@ 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); +QDisc* qdisc_drop(QDisc *qdisc); + 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); diff --git a/src/network/tc/tclass.c b/src/network/tc/tclass.c index 0452cc99a8..9e6032b35a 100644 --- a/src/network/tc/tclass.c +++ b/src/network/tc/tclass.c @@ -255,6 +255,33 @@ static void log_tclass_debug(TClass *tclass, Link *link, const char *str) { strna(tclass_get_tca_kind(tclass))); } +TClass* tclass_drop(TClass *tclass) { + QDisc *qdisc; + Link *link; + + assert(tclass); + + link = ASSERT_PTR(tclass->link); + + /* Also drop all child qdiscs assigned to the class. */ + SET_FOREACH(qdisc, link->qdiscs) { + if (qdisc->parent != tclass->classid) + continue; + + qdisc_drop(qdisc); + } + + tclass_enter_removed(tclass); + + if (tclass->state == 0) { + log_tclass_debug(tclass, link, "Forgetting"); + tclass = tclass_free(tclass); + } else + log_tclass_debug(tclass, link, "Removed"); + + return tclass; +} + static int tclass_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, TClass *tclass) { int r; @@ -464,14 +491,9 @@ int manager_rtnl_process_tclass(sd_netlink *rtnl, sd_netlink_message *message, M break; case RTM_DELTCLASS: - if (tclass) { - tclass_enter_removed(tclass); - if (tclass->state == 0) { - log_tclass_debug(tclass, link, "Forgetting"); - tclass_free(tclass); - } else - log_tclass_debug(tclass, link, "Removed"); - } else + if (tclass) + (void) tclass_drop(tclass); + else log_tclass_debug(tmp, link, "Kernel removed unknown"); break; diff --git a/src/network/tc/tclass.h b/src/network/tc/tclass.h index 606bb3fef3..f0ee318c76 100644 --- a/src/network/tc/tclass.h +++ b/src/network/tc/tclass.h @@ -58,6 +58,8 @@ 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); +TClass* tclass_drop(TClass *tclass); + int link_find_tclass(Link *link, uint32_t classid, TClass **ret); int link_request_tclass(Link *link, TClass *tclass);