From a7b5bb233f3da89909c4b5086e90fc87dbe25609 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 18 May 2026 12:25:41 +0200 Subject: [PATCH] airoha: Add the capability to offload dscp field via netfilter flowtable 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 Link: https://github.com/openwrt/openwrt/pull/23423 Signed-off-by: Christian Marangi --- ...owtable-Add-the-capability-to-offloa.patch | 150 ++++++++++++++++++ ...w-QoS-parameter-according-to-the-pac.patch | 94 +++++++++++ 2 files changed, 244 insertions(+) create mode 100644 target/linux/airoha/patches-6.12/915-01-net-netfilter-flowtable-Add-the-capability-to-offloa.patch create mode 100644 target/linux/airoha/patches-6.12/915-02-net-airoha-Set-hw-QoS-parameter-according-to-the-pac.patch 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; +