summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGennaro Cimmino2026-10-04 18:39:27 +0000
committerMarkus Stockhausen2026-10-04 19:46:56 +0000
commitf7950775283a36b6bd8de40fc8f14813d4f320b1 (patch)
tree8c080aa2fc9e4f9d481f0159d83ee16e53f7f0fa
parent5a7b0432844f40a3b352f5d65d3913c959e29190 (diff)
realtek: l3: treat a dscp 0 main rule as restrictedHEADmastermain
A rule given an explicit dscp selector keeps it in the family's own part of the rule, with a flag that tells dscp 0 from no selector at all. fib4_rule_default() and fib6_rule_default() only test the dscp value, so "dscp 0 lookup main" passed for an unrestricted main rule: packets with any other dscp go on to the next rules in the kernel, and the hardware forwarded them by main all the same. Only the family's own callbacks see that part of the rule, and its fill callback reports an explicit selector as FRA_DSCP. Run it into a scratch buffer and count a local or main rule with FRA_DSCP, or one that cannot be read out, as restricted. Tested on a Hasivo S1100W-8XGT-SE (RTL9303) with L3 offload enabled: a prefix routed in main via a host on another VLAN, blackholed in table 100, with "dscp 0 lookup main" ahead of a rule sending the sender's subnet to table 100. Echoes with dscp 8: without this change the row keeps forwarding and all 5 reach the host, with it the row traps and none do, for IPv4 and IPv6. With it, echoes with dscp 0 still reach the host, routed by the kernel through main. Assisted-by: Claude:claude-opus-5-5 Signed-off-by: Gennaro Cimmino <gcimmino@rayonra.net> Link: https://github.com/openwrt/openwrt/pull/25618 Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
-rw-r--r--target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/l3.c37
1 files changed, 32 insertions, 5 deletions
diff --git a/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/l3.c b/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/l3.c
index f90ed89d1a..f0ea0f649a 100644
--- a/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/l3.c
+++ b/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/l3.c
@@ -2580,20 +2580,47 @@ static int otto_l3_fib_del_v6(struct otto_l3_ctrl *ctrl, struct fib6_entry_notif
return 0;
}
-static bool otto_l3_rule_default(const struct fib_rule *rule, int family)
+/* A dscp selector the rule was given explicitly, 0 included, is kept in the
+ * family's own part of the rule, which only the family's callbacks see; its
+ * fill callback reports one as FRA_DSCP. A rule that cannot be read out counts
+ * as having one.
+ */
+static bool otto_l3_rule_dscp(struct fib_rules_ops *ops, struct fib_rule *rule)
{
+ struct fib_rule_hdr *frh;
+ struct sk_buff *skb;
+ bool dscp = true;
+
+ skb = alloc_skb(sizeof(*frh) + ops->nlmsg_payload(rule), GFP_KERNEL);
+ if (!skb)
+ return true;
+
+ frh = skb_put_zero(skb, sizeof(*frh));
+ if (!ops->fill(rule, skb, frh))
+ dscp = nla_find((struct nlattr *)(frh + 1), skb->len - sizeof(*frh), FRA_DSCP);
+
+ consume_skb(skb);
+
+ return dscp;
+}
+
+static bool otto_l3_rule_default(struct fib_rules_ops *ops, struct fib_rule *rule,
+ int family)
+{
+ bool def = false;
+
/* The kernel's own test leaves the protocol and the mark mask out */
if (rule->ip_proto || rule->mark_mask)
return false;
#if IS_ENABLED(CONFIG_IP_MULTIPLE_TABLES)
if (family == AF_INET)
- return fib4_rule_default(rule);
+ def = fib4_rule_default(rule);
#endif
#if IS_REACHABLE(CONFIG_IPV6) && IS_ENABLED(CONFIG_IPV6_MULTIPLE_TABLES)
if (family == AF_INET6)
- return fib6_rule_default(rule);
+ def = fib6_rule_default(rule);
#endif
- return false;
+ return def && !otto_l3_rule_dscp(ops, rule);
}
/* The switch looks a destination up in one table, so it forwards the way the
@@ -2631,7 +2658,7 @@ static bool otto_l3_rules_allow(int family)
break;
}
- if (otto_l3_rule_default(rule, family)) {
+ if (otto_l3_rule_default(ops, rule, family)) {
if (rule->table == RT_TABLE_MAIN) {
main_seen = true;
main_pref = rule->pref;