From: Yu Watanabe Date: Sat, 7 Oct 2023 05:20:38 +0000 (+0900) Subject: network/tc: drop child tree of traffic control nodes on remove X-Git-Tag: v255-rc1~294^2~5 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=be8e93390003e45acbb318c6e1e48fbc3c772f78;p=thirdparty%2Fsystemd.git 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. --- diff --git a/src/network/tc/qdisc.c b/src/network/tc/qdisc.c index 7bb95ede754..828fe9ab829 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 155e2adf248..86db44763bf 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 0452cc99a87..9e6032b35a6 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 606bb3fef33..f0ee318c76f 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);