diff --git a/target/linux/airoha/patches-6.12/915-01-net-netfilter-flowtable-Add-the-capability-to-offloa.patch b/target/linux/airoha/patches-6.12/915-01-net-netfilter-flowtable-Add-the-capability-to-offloa.patch new file mode 100644 index 0000000000..e11d368888 --- /dev/null +++ b/target/linux/airoha/patches-6.12/915-01-net-netfilter-flowtable-Add-the-capability-to-offloa.patch @@ -0,0 +1,150 @@ +From 6408cdca652b1f85e5b8582c283203d11f4dedcb Mon Sep 17 00:00:00 2001 +Message-ID: <6408cdca652b1f85e5b8582c283203d11f4dedcb.1779086987.git.lorenzo@kernel.org> +From: Lorenzo Bianconi +Date: Sun, 17 May 2026 21:11:27 +0200 +Subject: [PATCH net-next 1/2] net: netfilter: flowtable: Add the capability to + offload dscp field + +Introduce the capability to hw offload via netfilter flowtable APIs the +IP TOS info. Implement the sw offloading for DSCP field via the +netfilter flowtable APIs. + +Signed-off-by: Lorenzo Bianconi +--- + include/net/netfilter/nf_flow_table.h | 2 ++ + net/netfilter/nf_flow_table_ip.c | 12 ++++++++++++ + net/netfilter/nf_flow_table_offload.c | 5 +++++ + net/netfilter/nft_flow_offload.c | 22 ++++++++++++++++++++++ + 4 files changed, 41 insertions(+) + +--- a/include/net/netfilter/nf_flow_table.h ++++ b/include/net/netfilter/nf_flow_table.h +@@ -29,6 +29,7 @@ struct nf_flow_key { + struct flow_dissector_key_ipv4_addrs ipv4; + struct flow_dissector_key_ipv6_addrs ipv6; + }; ++ struct flow_dissector_key_ip ip; + struct flow_dissector_key_keyid enc_key_id; + union { + struct flow_dissector_key_ipv4_addrs enc_ipv4; +@@ -138,6 +139,7 @@ struct flow_offload_tuple { + encap_num:2, + in_vlan_ingress:2; + u16 mtu; ++ u8 dscp; + union { + struct { + struct dst_entry *dst_cache; +--- a/net/netfilter/nf_flow_table_ip.c ++++ b/net/netfilter/nf_flow_table_ip.c +@@ -372,6 +372,7 @@ static int nf_flow_offload_forward(struc + struct flow_offload *flow; + unsigned int thoff, mtu; + struct iphdr *iph; ++ u8 dscp; + + dir = tuplehash->tuple.dir; + flow = container_of(tuplehash, struct flow_offload, tuplehash[dir]); +@@ -401,6 +402,12 @@ static int nf_flow_offload_forward(struc + iph = ip_hdr(skb); + nf_flow_nat_ip(flow, skb, thoff, dir, iph); + ++ dscp = FIELD_GET(INET_DSCP_MASK, ipv4_get_dsfield(iph)); ++ if (tuplehash->tuple.dscp != dscp) ++ ipv4_change_dsfield(iph, INET_ECN_MASK, ++ FIELD_PREP(INET_DSCP_MASK, ++ tuplehash->tuple.dscp)); ++ + ip_decrease_ttl(iph); + skb_clear_tstamp(skb); + +@@ -651,6 +658,7 @@ static int nf_flow_offload_ipv6_forward( + struct flow_offload *flow; + unsigned int thoff, mtu; + struct ipv6hdr *ip6h; ++ u8 dscp; + + dir = tuplehash->tuple.dir; + flow = container_of(tuplehash, struct flow_offload, tuplehash[dir]); +@@ -679,6 +687,12 @@ static int nf_flow_offload_ipv6_forward( + ip6h = ipv6_hdr(skb); + nf_flow_nat_ipv6(flow, skb, dir, ip6h); + ++ dscp = FIELD_GET(INET_DSCP_MASK, ipv6_get_dsfield(ip6h)); ++ if (tuplehash->tuple.dscp != dscp) ++ ipv6_change_dsfield(ip6h, INET_ECN_MASK, ++ FIELD_PREP(INET_DSCP_MASK, ++ tuplehash->tuple.dscp)); ++ + ip6h->hop_limit--; + skb_clear_tstamp(skb); + +--- a/net/netfilter/nf_flow_table_offload.c ++++ b/net/netfilter/nf_flow_table_offload.c +@@ -103,6 +103,7 @@ static int nf_flow_rule_match(struct nf_ + NF_FLOW_DISSECTOR(match, FLOW_DISSECTOR_KEY_BASIC, basic); + NF_FLOW_DISSECTOR(match, FLOW_DISSECTOR_KEY_IPV4_ADDRS, ipv4); + NF_FLOW_DISSECTOR(match, FLOW_DISSECTOR_KEY_IPV6_ADDRS, ipv6); ++ NF_FLOW_DISSECTOR(match, FLOW_DISSECTOR_KEY_IP, ip); + NF_FLOW_DISSECTOR(match, FLOW_DISSECTOR_KEY_TCP, tcp); + NF_FLOW_DISSECTOR(match, FLOW_DISSECTOR_KEY_PORTS, tp); + +@@ -168,6 +169,10 @@ static int nf_flow_rule_match(struct nf_ + match->dissector.used_keys |= BIT_ULL(key->control.addr_type); + mask->basic.n_proto = 0xffff; + ++ key->ip.tos = FIELD_PREP(INET_DSCP_MASK, tuple->dscp); ++ mask->ip.tos = 0xff; ++ match->dissector.used_keys |= BIT_ULL(FLOW_DISSECTOR_KEY_IP); ++ + switch (tuple->l4proto) { + case IPPROTO_TCP: + key->tcp.flags = 0; +--- a/net/netfilter/nft_flow_offload.c ++++ b/net/netfilter/nft_flow_offload.c +@@ -8,6 +8,7 @@ + #include + #include + #include ++#include + #include /* for ipv4 options. */ + #include + #include +@@ -279,6 +280,27 @@ static int nft_flow_route(const struct n + return 0; + } + ++static void nft_flow_set_dscp(const struct nft_pktinfo *pkt, ++ struct flow_offload *flow, ++ enum ip_conntrack_dir dir) ++{ ++ struct flow_offload_tuple *tuple = &flow->tuplehash[dir].tuple; ++ struct sk_buff *skb = pkt->skb; ++ ++ switch (skb->protocol) { ++ case htons(ETH_P_IP): ++ tuple->dscp = FIELD_GET(INET_DSCP_MASK, ++ ipv4_get_dsfield(ip_hdr(skb))); ++ break; ++ case htons(ETH_P_IPV6): ++ tuple->dscp = FIELD_GET(INET_DSCP_MASK, ++ ipv6_get_dsfield(ipv6_hdr(skb))); ++ break; ++ default: ++ break; ++ } ++} ++ + static bool nft_flow_offload_skip(struct sk_buff *skb, int family) + { + if (skb_sec_path(skb)) +@@ -371,6 +393,9 @@ static void nft_flow_offload_eval(const + if (!flow) + goto err_flow_alloc; + ++ nft_flow_set_dscp(pkt, flow, dir); ++ nft_flow_set_dscp(pkt, flow, !dir); ++ + flow_offload_route_init(flow, &route); + if (tcph) + flow_offload_ct_tcp(ct); diff --git a/target/linux/airoha/patches-6.12/915-02-net-airoha-Set-hw-QoS-parameter-according-to-the-pac.patch b/target/linux/airoha/patches-6.12/915-02-net-airoha-Set-hw-QoS-parameter-according-to-the-pac.patch new file mode 100644 index 0000000000..15eded87d3 --- /dev/null +++ b/target/linux/airoha/patches-6.12/915-02-net-airoha-Set-hw-QoS-parameter-according-to-the-pac.patch @@ -0,0 +1,94 @@ +From b9870ade9498f4119d3f8f8368fcd13e1fa0c7c9 Mon Sep 17 00:00:00 2001 +Message-ID: +In-Reply-To: <6408cdca652b1f85e5b8582c283203d11f4dedcb.1779086987.git.lorenzo@kernel.org> +References: <6408cdca652b1f85e5b8582c283203d11f4dedcb.1779086987.git.lorenzo@kernel.org> +From: Lorenzo Bianconi +Date: Mon, 18 May 2026 08:36:20 +0200 +Subject: [PATCH net-next 2/2] net: airoha: Set hw QoS parameter according to + the packet dscp + +Introduce the capability to hw offload via netfilter flowtable APIs the +IP TOS info in order to configure hw queue and dscp field. + +Signed-off-by: Lorenzo Bianconi +--- + drivers/net/ethernet/airoha/airoha_ppe.c | 24 ++++++++++++++++++------ + 1 file changed, 18 insertions(+), 6 deletions(-) + +--- a/drivers/net/ethernet/airoha/airoha_ppe.c ++++ b/drivers/net/ethernet/airoha/airoha_ppe.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + + #include "airoha_regs.h" + #include "airoha_eth.h" +@@ -298,7 +299,7 @@ static int airoha_ppe_foe_entry_prepare( + struct airoha_foe_entry *hwe, + struct net_device *dev, int type, + struct airoha_flow_data *data, +- int l4proto) ++ int l4proto, u8 dsfield) + { + u32 qdata = FIELD_PREP(AIROHA_FOE_SHAPER_ID, 0x7f), ports_pad, val; + int wlan_etype = -EINVAL, dsa_port = airoha_get_dsa_port(&dev); +@@ -331,7 +332,7 @@ static int airoha_ppe_foe_entry_prepare( + info.wcid); + } else { + struct airoha_gdm_port *port = netdev_priv(dev); +- u8 pse_port, channel; ++ u8 pse_port, channel, priority; + + if (!airoha_is_valid_gdm_port(eth, port)) + return -EINVAL; +@@ -350,9 +351,13 @@ static int airoha_ppe_foe_entry_prepare( + */ + channel = dsa_port >= 0 ? dsa_port : port->id; + channel = channel % AIROHA_NUM_QOS_CHANNELS; +- qdata |= FIELD_PREP(AIROHA_FOE_CHANNEL, channel); ++ priority = rt_tos2priority(dsfield); ++ priority = priority % AIROHA_NUM_QOS_QUEUES; ++ qdata |= FIELD_PREP(AIROHA_FOE_CHANNEL, channel) | ++ FIELD_PREP(AIROHA_FOE_QID, priority); + + val |= FIELD_PREP(AIROHA_FOE_IB2_PSE_PORT, pse_port) | ++ FIELD_PREP(AIROHA_FOE_IB2_DSCP, dsfield) | + AIROHA_FOE_IB2_PSE_QOS; + /* For downlink traffic consume SRAM memory for hw + * forwarding descriptors queue. +@@ -1044,9 +1049,9 @@ static int airoha_ppe_flow_offload_repla + struct net_device *odev = NULL; + struct flow_action_entry *act; + struct airoha_foe_entry hwe; ++ u8 dsfield = 0, l4proto = 0; + int err, i, offload_type; + u16 addr_type = 0; +- u8 l4proto = 0; + + if (rhashtable_lookup(ð->flow_table, &f->cookie, + airoha_flow_table_params)) +@@ -1076,6 +1081,13 @@ static int airoha_ppe_flow_offload_repla + return -EOPNOTSUPP; + } + ++ if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IP)) { ++ struct flow_match_ip match; ++ ++ flow_rule_match_ip(rule, &match); ++ dsfield = match.key->tos; ++ } ++ + switch (addr_type) { + case 0: + offload_type = PPE_PKT_TYPE_BRIDGE; +@@ -1141,7 +1153,7 @@ static int airoha_ppe_flow_offload_repla + return -EINVAL; + + err = airoha_ppe_foe_entry_prepare(eth, &hwe, odev, offload_type, +- &data, l4proto); ++ &data, l4proto, dsfield); + if (err) + return err; +