Thread (1 message) 1 message, 1 author, 18d ago

Re: [PATCH net 2/3] net/sched: Handle TC_ACT_REDIRECT from qdisc filter chains

From: Jamal Hadi Salim <jhs@mojatatu.com>
Date: 2026-06-28 12:28:58
Also in: bpf, sashiko-reviews

On Sat, Jun 27, 2026 at 12:52 PM [off-list ref] wrote:
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] Removal of TC_ACT_REDIRECT support from qevents (tcf_qevent_handle) breaks existing eBPF redirect functionality.
- [Low] pr_warn_once() used inside a static inline function in a header file will print multiple times.
--

commit d96e142c03f9c1a1e9ac2e1d8c8fe26605053b10
Author: Jamal Hadi Salim [off-list ref]

net/sched: Handle TC_ACT_REDIRECT from qdisc filter chains

When a TC filter attached to a qdisc filter chain returns TC_ACT_REDIRECT,
the redirect is silently lost. This patch adds a tcf_classify_qdisc()
wrapper to convert TC_ACT_REDIRECT to TC_ACT_SHOT and drops the packet.
It also removes the TC_ACT_REDIRECT case from tcf_qevent_handle() since
it is handled by the wrapper.
quoted
diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h
index 3bd08d7f39c18..3a542a72e9a55 100644
--- a/include/net/pkt_cls.h
+++ b/include/net/pkt_cls.h
[ ... ]
quoted
@@ -159,6 +159,19 @@ static inline int tcf_classify(struct sk_buff *skb,

 #endif

+static inline int tcf_classify_qdisc(struct sk_buff *skb,
+                                  const struct tcf_proto *tp,
+                                  struct tcf_result *res, bool compat_mode)
+{
+     int ret = tcf_classify(skb, NULL, tp, res, compat_mode);
+
+     if (unlikely(ret == TC_ACT_REDIRECT)) {
+             pr_warn_once("TC_ACT_REDIRECT from qdisc filter chains is not supported; use eBPF with clsact or mirred redirect instead\n");
[Severity: Low]
Is this going to print multiple times instead of strictly once globally?

Because tcf_classify_qdisc() is a static inline function in a header file,
each C file including it (like the various qdisc modules) will create its own
local instance of the static __already_done variable used by pr_warn_once().
This was intentional. I used WARN_ONCE() initially, but NIPA testing
may consider that as something "bad". In any case, this usage is
common, just ignore it.
quoted
+             ret = TC_ACT_SHOT;
+     }
+     return ret;
+}
+
 static inline unsigned long
 __cls_set_class(unsigned long *clp, unsigned long cl)
 {
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index 3e67600a4a1a1..3ca56d060e28f 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -4033,7 +4033,7 @@ struct sk_buff *tcf_qevent_handle(struct tcf_qevent *qe, struct Qdisc *sch, stru

      fl = rcu_dereference_bh(qe->filter_chain);

-     switch (tcf_classify(skb, NULL, fl, &cl_res, false)) {
+     switch (tcf_classify_qdisc(skb, fl, &cl_res, false)) {
[Severity: High]
Does this break existing eBPF redirect functionality for qevents?
Again, design intent. I will update the commit message to state this
clearly with the following text:
---
Remove the TC_ACT_REDIRECT case from tcf_qevent_handle().
skb_do_redirect() belongs in the BPF plumbing layer (net/core/), not
in net/sched/. The case was never consistent with the rest of the
qdisc classification infrastructure, where no classify function
handles
TC_ACT_REDIRECT.
---

IMO, it appears to have been TheLinuxWay(tm) i.e a cut-and-paste from
existing code on day 1 of  the qevent introduction rather than a
deliberate design decision.
Ccing Petr to see if he thinks differently.

cheers,
jamal
Prior to this patch, tcf_qevent_handle() correctly handled TC_ACT_REDIRECT
by calling skb_do_redirect(skb). By using the tcf_classify_qdisc() wrapper
here, TC_ACT_REDIRECT is unconditionally converted to TC_ACT_SHOT. This
inadvertently drops packets that were legitimately redirecting from qevents.
quoted
      case TC_ACT_SHOT:
              qdisc_qstats_drop(sch);
              __qdisc_drop(skb, to_free);
@@ -4045,10 +4045,6 @@ struct sk_buff *tcf_qevent_handle(struct tcf_qevent *qe, struct Qdisc *sch, stru
              __qdisc_drop(skb, to_free);
              *ret = __NET_XMIT_STOLEN;
              return NULL;
-     case TC_ACT_REDIRECT:
-             skb_do_redirect(skb);
-             *ret = __NET_XMIT_STOLEN;
-             return NULL;
      case TC_ACT_CONSUMED:
              *ret = __NET_XMIT_STOLEN;
              return NULL;
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260626165156.169012-1-jhs@mojatatu.com?part=2
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help