Merge branch 'net-sched-fix-action-batch-failure-cleanup'

Xuanqiang Luo says:

====================
net/sched: fix action batch failure cleanup

Failed batched RTM_NEWACTION requests can leak action references and
reserved IDR indices when cleanup encounters a filter-bound action.

Patch 1 fixes the failure cleanup.

Patch 2 adds tc-testing regression coverage.

Failure reproduction (key output excerpts):

  python3 tdc.py -f tc-tests/actions/gact-rollback.json

not ok 1 e3b1 - Failed action batch releases a bound action reference
	Could not match regex pattern. Verify command output:
[...]
	 index 1 ref 3 bind 1

not ok 2 e3b2 - Failed action batch releases entries after a bound action
	Command exited with 255, expected 0
RTNETLINK answers: Resource temporarily unavailable
We have an error talking to the kernel

not ok 3 e3b3 - Failed action batch releases repeated references to a bound action
	Could not match regex pattern. Verify command output:
[...]
	 index 1 ref 4 bind 1
====================

Link: https://patch.msgid.link/20260909070336.32979-1-xuanqiang.luo@linux.dev
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2026-09-10 09:06:07 -07:00
commit 5096947508
2 changed files with 80 additions and 7 deletions

View File

@ -1200,18 +1200,13 @@ EXPORT_SYMBOL(tcf_action_exec);
int tcf_action_destroy(struct tc_action *actions[], int bind)
{
const struct tc_action_ops *ops;
struct tc_action *a;
int ret = 0, i;
tcf_act_for_each_action(i, a, actions) {
actions[i] = NULL;
ops = a->ops;
ret = __tcf_idr_release(a, bind, true);
if (ret == ACT_P_DELETED)
module_put(ops->owner);
else if (ret < 0)
return ret;
/* Drop our reference even if the action is still bound to a filter. */
ret = tcf_idr_release(a, bind);
}
return ret;
}

View File

@ -0,0 +1,78 @@
[
{
"id": "e3b1",
"name": "Failed action batch releases a bound action reference",
"category": [
"actions",
"gact"
],
"plugins": {
"requires": "nsPlugin"
},
"setup": [
"$TC qdisc add dev $DEV1 ingress",
"$TC actions add action pass index 1",
"$TC filter add dev $DEV1 protocol all ingress prio 1 matchall action gact index 1"
],
"cmdUnderTest": "$TC actions replace action pass index 1 action goto chain 42 index 3",
"expExitCode": "255",
"verifyCmd": "$TC actions ls action gact",
"matchPattern": "total acts 1.*index 1 ref 2 bind 1",
"matchCount": "1",
"teardown": [
"$TC qdisc del dev $DEV1 ingress"
]
},
{
"id": "e3b2",
"name": "Failed action batch releases entries after a bound action",
"category": [
"actions",
"gact"
],
"plugins": {
"requires": "nsPlugin"
},
"setup": [
"$TC qdisc add dev $DEV1 ingress",
"$TC actions add action pass index 1",
"$TC filter add dev $DEV1 protocol all ingress prio 1 matchall action gact index 1",
[
"$TC actions replace action pass index 1 action pass index 2 action goto chain 42 index 3",
255
]
],
"cmdUnderTest": "$TC actions add action pass index 2",
"expExitCode": "0",
"verifyCmd": "$TC actions ls action gact",
"matchPattern": "total acts 2.*index 1 ref 2 bind 1.*index 2 ref 1 bind 0",
"matchCount": "1",
"teardown": [
"$TC qdisc del dev $DEV1 ingress"
]
},
{
"id": "e3b3",
"name": "Failed action batch releases repeated references to a bound action",
"category": [
"actions",
"gact"
],
"plugins": {
"requires": "nsPlugin"
},
"setup": [
"$TC qdisc add dev $DEV1 ingress",
"$TC actions add action pass index 1",
"$TC filter add dev $DEV1 protocol all ingress prio 1 matchall action gact index 1"
],
"cmdUnderTest": "$TC actions replace action pass index 1 action pass index 1 action goto chain 42 index 3",
"expExitCode": "255",
"verifyCmd": "$TC actions ls action gact",
"matchPattern": "total acts 1.*index 1 ref 2 bind 1",
"matchCount": "1",
"teardown": [
"$TC qdisc del dev $DEV1 ingress"
]
}
]