diff --git a/src/network/tc/qdisc.c b/src/network/tc/qdisc.c index 55ce16600a..38dee2c001 100644 --- a/src/network/tc/qdisc.c +++ b/src/network/tc/qdisc.c @@ -285,37 +285,57 @@ int link_find_qdisc(Link *link, uint32_t handle, const char *kind, QDisc **ret) return -ENOENT; } -QDisc* qdisc_drop(QDisc *qdisc) { +void qdisc_mark_recursive(QDisc *qdisc) { TClass *tclass; - Link *link; assert(qdisc); + assert(qdisc->link); - link = ASSERT_PTR(qdisc->link); + if (qdisc_is_marked(qdisc)) + return; - qdisc_mark(qdisc); /* To avoid stack overflow. */ - - /* also drop all child classes assigned to the qdisc. */ - SET_FOREACH(tclass, link->tclasses) { - if (tclass_is_marked(tclass)) - continue; + qdisc_mark(qdisc); + /* also mark all child classes assigned to the qdisc. */ + SET_FOREACH(tclass, qdisc->link->tclasses) { if (TC_H_MAJ(tclass->classid) != qdisc->handle) continue; - tclass_drop(tclass); + tclass_mark_recursive(tclass); } +} - qdisc_unmark(qdisc); - qdisc_enter_removed(qdisc); +void link_qdisc_drop_marked(Link *link) { + QDisc *qdisc; - if (qdisc->state == 0) { - log_qdisc_debug(qdisc, link, "Forgetting"); - qdisc = qdisc_free(qdisc); - } else - log_qdisc_debug(qdisc, link, "Removed"); + assert(link); - return qdisc; + SET_FOREACH(qdisc, link->qdiscs) { + if (!qdisc_is_marked(qdisc)) + continue; + + qdisc_unmark(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"); + } +} + +QDisc* qdisc_drop(QDisc *qdisc) { + assert(qdisc); + assert(qdisc->link); + + qdisc_mark_recursive(qdisc); + + /* link_qdisc_drop_marked() may invalidate qdisc, so run link_tclass_drop_marked() first. */ + link_tclass_drop_marked(qdisc->link); + link_qdisc_drop_marked(qdisc->link); + + return NULL; } static int qdisc_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, QDisc *qdisc) { diff --git a/src/network/tc/qdisc.h b/src/network/tc/qdisc.h index a62b9413ec..cbba1bef71 100644 --- a/src/network/tc/qdisc.h +++ b/src/network/tc/qdisc.h @@ -77,7 +77,9 @@ 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); +void qdisc_mark_recursive(QDisc *qdisc); QDisc* qdisc_drop(QDisc *qdisc); +void link_qdisc_drop_marked(Link *link); int link_find_qdisc(Link *link, uint32_t handle, const char *kind, QDisc **qdisc); diff --git a/src/network/tc/tclass.c b/src/network/tc/tclass.c index 63229ec6e8..fcbe8cbcf4 100644 --- a/src/network/tc/tclass.c +++ b/src/network/tc/tclass.c @@ -252,37 +252,56 @@ static void log_tclass_debug(TClass *tclass, Link *link, const char *str) { strna(tclass_get_tca_kind(tclass))); } -TClass* tclass_drop(TClass *tclass) { +void tclass_mark_recursive(TClass *tclass) { QDisc *qdisc; - Link *link; assert(tclass); + assert(tclass->link); - link = ASSERT_PTR(tclass->link); + if (tclass_is_marked(tclass)) + return; - tclass_mark(tclass); /* To avoid stack overflow. */ - - /* Also drop all child qdiscs assigned to the class. */ - SET_FOREACH(qdisc, link->qdiscs) { - if (qdisc_is_marked(qdisc)) - continue; + tclass_mark(tclass); + /* Also mark all child qdiscs assigned to the class. */ + SET_FOREACH(qdisc, tclass->link->qdiscs) { if (qdisc->parent != tclass->classid) continue; - qdisc_drop(qdisc); + qdisc_mark_recursive(qdisc); } +} - tclass_unmark(tclass); - tclass_enter_removed(tclass); +void link_tclass_drop_marked(Link *link) { + TClass *tclass; - if (tclass->state == 0) { - log_tclass_debug(tclass, link, "Forgetting"); - tclass = tclass_free(tclass); - } else - log_tclass_debug(tclass, link, "Removed"); + assert(link); - return tclass; + SET_FOREACH(tclass, link->tclasses) { + if (!tclass_is_marked(tclass)) + continue; + + tclass_unmark(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"); + } +} + +TClass* tclass_drop(TClass *tclass) { + assert(tclass); + + tclass_mark_recursive(tclass); + + /* link_tclass_drop_marked() may invalidate tclass, so run link_qdisc_drop_marked() first. */ + link_qdisc_drop_marked(tclass->link); + link_tclass_drop_marked(tclass->link); + + return NULL; } static int tclass_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, TClass *tclass) { diff --git a/src/network/tc/tclass.h b/src/network/tc/tclass.h index e73e23c97f..85df57d42c 100644 --- a/src/network/tc/tclass.h +++ b/src/network/tc/tclass.h @@ -58,7 +58,9 @@ 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); +void tclass_mark_recursive(TClass *tclass); TClass* tclass_drop(TClass *tclass); +void link_tclass_drop_marked(Link *link); int link_find_tclass(Link *link, uint32_t classid, TClass **ret);