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);