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.
This commit is contained in:
Yu Watanabe
2023-10-07 21:35:16 +09:00
parent 0708c4fbdb
commit be8e933900
4 changed files with 64 additions and 16 deletions
+30 -8
View File
@@ -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;
+2
View File
@@ -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);
+30 -8
View File
@@ -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;
+2
View File
@@ -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);